home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 2000 April: Mac OS SDK / Dev.CD Apr 00 SDK1.toast / Development Kits / Mac OS / Open Transport 1.3 / Open Transport SDK / Open Tpt Module Developer / Samples / DLPI Template / dlpiether.c next >
Encoding:
C/C++ Source or Header  |  1998-04-30  |  91.2 KB  |  3,322 lines  |  [TEXT/MPS ]

  1. /*
  2.     File:        dlpiether.c
  3.  
  4.     Contains:    Code to implement the DLPI template
  5.                  ** dlpiether.c 5.46, last change 28 Mar 1996
  6.  
  7.     Copyright:    © 1995, 1996 by Mentat Inc. and Apple Computer, Inc., all rights reserved.
  8.  
  9. */
  10.  
  11. #ifndef __DLPIETHER__
  12. #include "dlpiether.h"
  13. #endif
  14.  
  15. /*******************************************************************************
  16. ** Some defines
  17. ********************************************************************************/
  18.     
  19. #define nilp(type)        ((type*)0)
  20. #define A_CNT(arr)        (sizeof(arr)/sizeof(arr[0]))
  21. #define A_END(arr)        (&arr[A_CNT(arr)])
  22. #define A_LAST(arr)     (&arr[A_CNT(arr)-1])
  23. #define mi_qprocson(a)    /* Nothing */
  24. #define put(q, mp)        puthere(q, mp);
  25.  
  26. int mi_strlog (queue_t * q, ...);
  27.  
  28. /*******************************************************************************
  29. ** Some private structures
  30. ********************************************************************************/
  31.  
  32. /*
  33.  * Structure used for maintaining the list of multicast and physical
  34.  * addresses in dle_hw_addr_list.  The dleax_dlea portion of this structure
  35.  * is used by board-specific code to find out which multicast addresses
  36.  * should be received; this list is passed to the hardware address
  37.  * filter routine.
  38.  */
  39. typedef struct dle_addrx_s {
  40.     dle_addr_t        dleax_dlea;        /* Address structure. */
  41.     UInt32            dleax_ref_cnt;    /* Number of streams using this addr. */
  42. } dle_addrx_t;
  43.  
  44. #define    dleax_next    dleax_dlea.dlea_next
  45. #define    dleax_addr    dleax_dlea.dlea_addr
  46.  
  47. /*
  48.  * Structure for holding bind information; one is created for each DL_BIND_REQ,
  49.  * for each DL_SUBS_BIND_REQ/DL_PEER_BIND, and for each promiscuous setting.
  50.  * These structures are linked into the requesting stream's dcl structure
  51.  * (through bind_next) and are linked into the dle's bind hash table
  52.  * or one of the promiscuous match lists (through bind_hash_next and/or
  53.  * bind_sap_next).
  54.  *
  55.  * Each hash chain in the hash table is linked with the bind_hash_next field.
  56.  * The bound sap is used to hash to the right chain in the table, and there is
  57.  * exactly one bind structure in the chain followed with bind_hash_next for any
  58.  * sap.  Any additional binds for the same sap are linked through bind_sap_next
  59.  * from the bind in the primary hash chain.
  60.  *
  61.  * The promiscuous lists are headed by various fields in the dle structure
  62.  * (dle_match_any, etc.).  These lists are linked with the bind_sap_next field. 
  63.  * This allows dle_inbound_finish to loop through all similar bind structures 
  64.  * following bind_sap_next.
  65.  */
  66. typedef struct bind_s {
  67.     struct bind_s    * bind_next;    /* Link field for dle_bind_list */
  68.     UInt32            bind_flags;        /* Defined below */
  69.     UInt32            bind_sap;        /* Sap value: Ethertype or SNAP value */
  70.     struct bind_s    * bind_hash_next;/* Link field for hash table */
  71.     struct dcl_s    * bind_dcl;        /* Back pointer to client stream */
  72.     struct bind_s    * bind_sap_next;/* Link field for multiple binds to */
  73.                                     /* same sap or for multiple promiscuous*/
  74.                                     /* settings of the same flavor. */
  75. } bind_t;
  76.  
  77. /*
  78.  * Bind flags.
  79.  * NOTE: the SAP_HASH_BITS must fit within bits given by DLE_SAP_HASH_VALUE.
  80.  */
  81. #define    F_BIND_SNAP                    0x1        /* 802.2 with SNAP binding */
  82. #define    F_BIND_802                    0x2        /* Vanilla, non-SNAP binding */
  83. #define    F_BIND_IPX                    0x4        /* Raw formatting for old-style IPX */
  84. #define    F_BIND_SNAP_PENDING            0x8        /* Temporary flag used between bind */
  85.                                             /* and subsbind */
  86. #define    F_BIND_SAP_HASH_BITS        (F_BIND_SNAP | F_BIND_802 | F_BIND_IPX | F_BIND_SNAP_PENDING)
  87.  
  88. #define    F_BIND_MATCH_MATCHED        0x20
  89. #define    F_BIND_HASH                    0x40
  90.  
  91. /* Inbound packet may be any 802.x format packet */
  92. #define    F_BIND_MATCH_ANY_802        0x100
  93.  
  94. /* Inbound address may be anything */
  95. #define    F_BIND_MATCH_ANY            0x200
  96.  
  97. /* Inbound addr may be any multicast */
  98. #define    F_BIND_MATCH_ANY_MULTICAST    0x400
  99.  
  100. /*
  101.  * Inbound address must match dle_current_addr.  Note that this flag is
  102.  * not checked when processing inbound packets for binds marked F_BIND_HASH;
  103.  * it is always on in this case.  The flag is set when the creating the
  104.  * binds for debugging purposes; one of the match flags is always set.
  105.  */
  106. #define    F_BIND_MATCH_LOCAL            0x800
  107.  
  108. #define    F_BIND_PROMISCUOUS_MASK    (F_BIND_MATCH_ANY | F_BIND_MATCH_ANY_MULTICAST\
  109.                                     | F_BIND_MATCH_ANY_802 | F_BIND_MATCH_MATCHED)
  110.  
  111. #define    F_BIND_AUTO_XID                0x1000
  112. #define    F_BIND_AUTO_TEST            0x2000
  113.  
  114. /*
  115.  * Flag values for dcl_flags.  These are maintained by the common code
  116.  * and should *not* be changed by the board-specific code.
  117.  */
  118. #define    F_DCL_PROMISC_PHYS            0x1
  119. #define    F_DCL_PROMISC_MULTI            0x2
  120. #define    F_DCL_PROMISC_SAP            0x4
  121. #define    F_DCL_802                    0x8
  122. #define    F_DCL_SNAP                    0x10
  123. #define    F_DCL_IPX                    0x20
  124. #define    F_DCL_NOT_FAST_PATH            0x80    /* in dlpiether.h also */
  125. #define    F_DCL_AUTO_XID                0x100
  126. #define    F_DCL_AUTO_TEST                0x200
  127. #define    F_DCL_WANTS_RS_HEADER        0x400
  128. #define    F_DCL_WANTS_ERROR_PACKETS    0x800
  129. #define    F_DCL_PROMISCUOUS_MASK        (F_DCL_PROMISC_PHYS | F_DCL_PROMISC_MULTI \
  130.                                      | F_DCL_PROMISC_SAP)
  131.  
  132. #define    DLE_SAP_HASH_VALUE(sap,flags)    (((sap) ^ ((flags) & F_BIND_SAP_HASH_BITS)) & 63)
  133.  
  134. /* Offsets to LLC header fields */
  135. #define    LLC_DSAP_OFFSET                14
  136. #define    LLC_SSAP_OFFSET                15
  137. #define    LLC_CONTROL_OFFSET            16
  138.  
  139. /* Definitions for handling 802.2 LLC Test and XID messages. */
  140. #define    LLC_DATA_VALUE                0x3
  141. #define    LLC_TEST_VALUE                0xE3
  142. #define    LLC_XID_VALUE                0xAF
  143. #define    LLC_RESPONSE_BIT            0x01
  144. #define    LLC_POLL_FINAL_FLAG            0x10    /* Poll/Final bit */
  145. #define    XID_FORMAT_IDENTIFIER        0x81
  146.  
  147. /* Internal dispatch table for DLPI primitives. */
  148. typedef struct dle_dlpi_dispatch_s {
  149.     UInt32            dledd_primitive;
  150.     int                (*dledd_func)(queue_t *, mblk_t *);
  151.     UInt16            dledd_min_len;        /* Min request length required */
  152.     UInt16            dledd_reallocb_len;    /* Maximum ack length required */
  153.     UInt16            dledd_flags;        /* Defined below */
  154. } dle_dlpi_dispatch_t;
  155.  
  156. /* Flag values for dledd_flags */
  157. #define    F_MIEDD_OK_ACK_NEEDED    0x1
  158.  
  159. static    bind_t        * dle_bind_alloc(dcl_t * dcl, UInt32 sap, UInt32 flags);
  160. static    void        dle_bind_free(dle_t * dle, bind_t * bind);
  161. static    void        dle_bind_disable(dle_t * dle, bind_t * bind);
  162. static    void        dle_bind_enable(bind_t * bind);
  163. static    bind_t        * dle_bind_from_stuff(dcl_t * dcl, UInt32 flags, UInt32 sap);
  164. static    void        dle_bind_hash_insert(bind_t * bind);
  165. static    void        dle_bind_hash_remove(dle_t * dle, bind_t * bind);
  166. static    int            dle_bind_req(queue_t * q, mblk_t * mp);
  167. static    bind_t        ** dle_bindp_from_flags_and_sap(dle_t * dle, UInt32 flags, UInt32 sap);
  168. static    int            dle_disabmulti_req(queue_t * q, mblk_t * mp);
  169. static    int            dle_enabmulti_req(queue_t * q, mblk_t * mp);
  170. static    int            dle_get_statistics_req(queue_t * q, mblk_t * mp);
  171. static    UInt32        dle_hw_addr_dec_ref(dle_t * dle, UInt8 * addr);
  172. static UInt32        dle_hw_addr_inc_ref (dle_t * dle, UInt8 * addr);
  173. static    void        dle_hw_address_filter_reset(dle_t * dle);
  174. static    void        dle_inbound_802_broadcast(dle_t * dle, mblk_t * mp);
  175. static    mblk_t        * dle_inbound_special(dcl_t * dcl, mblk_t * mp1, size_t msg_len,
  176.                                           UInt8 * rptr, UInt32 flags);
  177. static    void        dle_inbound_xidtest(dle_t * dle, mblk_t * mp);
  178. static    int            dle_info_req(queue_t * q, mblk_t * mp);
  179. static    dle_addr_t    ** dle_dleap_from_addr(dcl_t * dcl, UInt8 * addr);
  180. static    int            dle_phys_addr_req(queue_t * q, mblk_t * mp);
  181. static    int            dle_promiscoff_req(queue_t * q, mblk_t * mp);
  182. static    int            dle_promiscon_req(queue_t * q, mblk_t * mp);
  183. static    void        dle_send_xidtest_response(bind_t * bind, mblk_t * mp);
  184. static    int            dle_subs_bind_req(queue_t * q, mblk_t * mp);
  185. static    int            dle_subs_unbind_req(queue_t * q, mblk_t * mp);
  186. static    void        dle_remove_all_my_binds(dcl_t * dcl);
  187. static    int            dle_unbind_req(queue_t * q, mblk_t * mp);
  188. static    mblk_t        * dle_wput_error(queue_t * q, mblk_t * mp, int dl_err, int sys_err);
  189. static    mblk_t        * dle_wput_ioctl(queue_t * q, mblk_t * mp);
  190. static    mblk_t        * dle_wput_proto(queue_t * q, mblk_t * mp);
  191. static    int            dle_xidtest(queue_t * q, mblk_t * mp);
  192.  
  193. static dle_dlpi_dispatch_t dle_dlpi_dispatch_table[] = {
  194. { DL_INFO_REQ,        dle_info_req,        sizeof(dl_info_req_t),
  195.             sizeof(dl_info_ack_t) + 6 + 13 },
  196. { DL_BIND_REQ,        dle_bind_req,        sizeof(dl_bind_req_t),
  197.             sizeof(dl_bind_ack_t) + 8 },
  198. { DL_ENABMULTI_REQ,    dle_enabmulti_req,    sizeof(dl_enabmulti_req_t) + 6,
  199.             sizeof(dl_ok_ack_t),    F_MIEDD_OK_ACK_NEEDED },
  200. { DL_DISABMULTI_REQ,    dle_disabmulti_req,    sizeof(dl_disabmulti_req_t) + 6,
  201.             sizeof(dl_ok_ack_t),    F_MIEDD_OK_ACK_NEEDED },
  202. { DL_UNBIND_REQ,    dle_unbind_req,        sizeof(dl_unbind_req_t),
  203.             sizeof(dl_ok_ack_t),    F_MIEDD_OK_ACK_NEEDED },
  204. { DL_SUBS_BIND_REQ,    dle_subs_bind_req,    sizeof(dl_subs_bind_req_t),
  205.             sizeof(dl_subs_bind_ack_t) + 13 },
  206. { DL_SUBS_UNBIND_REQ,    dle_subs_unbind_req,    sizeof(dl_unbind_req_t),
  207.             sizeof(dl_ok_ack_t),    F_MIEDD_OK_ACK_NEEDED },
  208. { DL_PROMISCON_REQ,    dle_promiscon_req,    sizeof(dl_promiscon_req_t),
  209.             sizeof(dl_ok_ack_t),    F_MIEDD_OK_ACK_NEEDED },
  210. { DL_PROMISCOFF_REQ,    dle_promiscoff_req,    sizeof(dl_promiscoff_req_t),
  211.             sizeof(dl_ok_ack_t),    F_MIEDD_OK_ACK_NEEDED },
  212. { DL_PHYS_ADDR_REQ,    dle_phys_addr_req,    sizeof(dl_phys_addr_req_t),
  213.             sizeof(dl_phys_addr_ack_t) + 6 },
  214. { DL_GET_STATISTICS_REQ, dle_get_statistics_req,sizeof(dl_get_statistics_req_t),
  215.             sizeof(dl_get_statistics_ack_t)
  216.             + sizeof(dle_interface_status_t)
  217.             + sizeof(dle_ethernet_status_t)
  218.             + 2 * sizeof(TOptionHeader) },
  219. { DL_TEST_REQ,        dle_xidtest,        sizeof(dl_test_req_t) + 6,
  220.             sizeof(dl_test_req_t),    0 },
  221. { DL_TEST_RES,        dle_xidtest,        sizeof(dl_test_res_t) + 6,
  222.             sizeof(dl_test_res_t),    0 },
  223. { DL_XID_REQ,        dle_xidtest,        sizeof(dl_xid_req_t) + 6,
  224.             sizeof(dl_xid_req_t),    0 },
  225. { DL_XID_RES,        dle_xidtest,        sizeof(dl_xid_res_t) + 6,
  226.             sizeof(dl_xid_res_t),    0 }
  227. };
  228.  
  229. /*
  230.  * Allocate and initialize a bind structure.  Called by dle_bind_req,
  231.  * dle_subs_bind_req and dle_promiscon_req.
  232.  */
  233. static bind_t *
  234. dle_bind_alloc (dcl_t * dcl, UInt32 sap, UInt32 flags)
  235. {
  236.     bind_t    * bind;
  237.  
  238.     bind = (bind_t *)OTAllocMem(sizeof(*bind));
  239.     if (bind == nilp(bind_t))
  240.         return bind;
  241.     bind->bind_sap = sap;
  242.     bind->bind_dcl = dcl;
  243.     bind->bind_flags = flags;
  244.     return bind;
  245. }
  246.  
  247. static void
  248. dle_bind_free (dle_t * dle, bind_t * bind)
  249. {
  250.     while (dle->dle_intr_active)
  251.         ;
  252.     OTFreeMem(bind);
  253. }
  254.  
  255. /*
  256.  * Remove a bind structure from the dle's list of all binds and from the
  257.  * hash table or match list.  This is called by dle_remove_all_my_binds,
  258.  * dle_subs_unbind_req, and dle_promiscoff_req.
  259.  */
  260. static void
  261. dle_bind_disable (dle_t * dle, bind_t * bind)
  262. {
  263.     unsigned int    changed = 0;
  264.  
  265.     dle_bind_hash_remove(dle, bind);
  266.  
  267.     if ((bind->bind_flags & F_BIND_MATCH_ANY_MULTICAST)
  268.         &&  --dle->dle_match_any_multicast_count == 0
  269.         &&  dle->dle_match_any_count == 0)
  270.         changed++;
  271.  
  272.     if ((bind->bind_flags & F_BIND_MATCH_ANY)
  273.         &&   --dle->dle_match_any_count == 0)
  274.         changed++;
  275.  
  276.     if (changed != 0)
  277.         dle_hw_address_filter_reset(dle);
  278.  
  279.     /* If there are no bindings, then shut the hardware down. */
  280.     if (--dle->dle_bound_count == 0)
  281.         (*dle->dle_hw.dlehw_stop)(dle_to_hw(dle));
  282. }
  283.  
  284. /*
  285.  * Enable a new bind for the dle.  If the board has not been kicked alive yet,
  286.  * do so by calling the hardware start routine.  This routine is called by
  287.  * dle_bind_req and dle_subs_bind_req.
  288.  * 
  289.  * Safety note: all binds for the dle must be inserted into the hash table by
  290.  * calling this routine and not by calling dle_bind_hash_insert directly. 
  291.  * dle_remove_all_my_binds calls dle_bind_disable for all binds in the dcl's
  292.  * bind list and dle_bind_disable decrements dle_bound_count for every bind
  293.  * removed.
  294.  */
  295. static void
  296. dle_bind_enable (bind_t * bind)
  297. {
  298.     dle_t            * dle;
  299.     unsigned int    changed;
  300.  
  301.     dle_bind_hash_insert(bind);
  302.  
  303.     /* Determine if we need to change the address filters on the hardware. */
  304.     dle = dcl_to_dle(bind->bind_dcl);
  305.     changed = (dle->dle_bound_count++ == 0);
  306.  
  307.     if (bind->bind_flags & F_BIND_MATCH_ANY)
  308.         changed |= (dle->dle_match_any_count++ == 0);
  309.  
  310.     if (bind->bind_flags & F_BIND_MATCH_ANY_MULTICAST)
  311.         changed |= (dle->dle_match_any_multicast_count++ == 0);
  312.     
  313.     if (changed != 0)
  314.         dle_hw_address_filter_reset(dle);
  315.  
  316.     /*
  317.      * If this is the first bind for this board, call the start routine to
  318.      * to initialize receive and transmit operations.  This is called after
  319.      * the possible call dle_hw_address_filter_reset in case we've changed
  320.      * the physical address or multicast filters.
  321.      */
  322.     if (dle->dle_bound_count == 1)
  323.         (*dle->dle_hw.dlehw_start)(dle_to_hw(dle));
  324. }
  325.  
  326. /*
  327.  * Find the start of the hash chain or match list for the requested flags
  328.  * and sap. This routine is called when looking up binds and when inserting
  329.  * new binds into the lookup tables.
  330.  */
  331. static bind_t **
  332. dle_bindp_from_flags_and_sap (dle_t * dle, UInt32 flags, UInt32 sap)
  333. {
  334.     bind_t    ** bindp;
  335.     bind_t    * bind;
  336.  
  337.     if (flags & F_BIND_HASH) {
  338.         bindp = (bind_t **)&dle->dle_sap_hash_tbl[DLE_SAP_HASH_VALUE(sap, flags)]; 
  339.         for ( ; (bind = bindp[0]) != nilp(bind_t); bindp = &bind->bind_hash_next) {
  340.             if (bind->bind_sap == sap)
  341.                 break;
  342.         }
  343.     } else if (flags & F_BIND_MATCH_MATCHED)
  344.         bindp = (bind_t **)&dle->dle_match_matched;
  345.     else if (flags & F_BIND_MATCH_ANY_MULTICAST)
  346.         bindp = (bind_t **)&dle->dle_match_any_multicast;
  347.     else if (flags & F_BIND_MATCH_ANY_802)
  348.         bindp = (bind_t **)&dle->dle_match_any_802;
  349.     else
  350.         bindp = (bind_t **)&dle->dle_match_any;
  351.     return bindp;
  352. }
  353.  
  354. /*
  355.  * Find the bind structure in the hash table for this stream (dcl) and for
  356.  * the requested flags and sap.
  357.  */
  358. static bind_t *
  359. dle_bind_from_stuff (dcl_t * dcl, UInt32 flags, UInt32 sap)
  360. {
  361.     dle_t    * dle = dcl_to_dle(dcl);
  362.     bind_t    * bind = *dle_bindp_from_flags_and_sap(dle, flags, sap);
  363.  
  364.     for ( ; bind != nilp(bind_t); bind = bind->bind_sap_next ) {
  365.         if ((bind->bind_flags & flags) == flags
  366.              &&  bind->bind_dcl == dcl)
  367.             return bind;
  368.     }
  369.     return bind;
  370. }
  371.  
  372. /*
  373.  * Add a new bind structure to the dle's list of all binds (dle_bind_list) and
  374.  * to the sap hash table or appropriate promiscuous match list.  This is called
  375.  * by dle_bind_enable and by dle_subs_bind_req.
  376.  */
  377. static void
  378. dle_bind_hash_insert (bind_t * bind)
  379. {
  380.     bind_t    ** bindp;
  381.     bind_t    * bind1;
  382.     dle_t    * dle = dcl_to_dle(bind->bind_dcl);
  383.  
  384.     bind->bind_sap_next = nilp(bind_t);
  385.     bind->bind_hash_next = nilp(bind_t);
  386.  
  387.     /* Add the bind to the list of all binds. */
  388.     bind->bind_next = dle->dle_bind_list;
  389.     dle->dle_bind_list = bind;
  390.  
  391.     /* Add the bind to the sap hash table. */
  392.     bindp = dle_bindp_from_flags_and_sap(dle, bind->bind_flags
  393.                         , bind->bind_sap);
  394.     bind1 = bindp[0];
  395.     if (bind1 != nilp(bind_t)) {
  396.         /*
  397.          * If there are other binds for the same sap, then we push the
  398.          * others down in the list (by linking them through our
  399.          * bind_sap_next) and make this bind structure the topmost
  400.          * in the hash chain.
  401.          */
  402.         bind->bind_hash_next = bind1->bind_hash_next;
  403.         bind1->bind_hash_next = nilp(bind_t);
  404.         bind->bind_sap_next = bind1;
  405.     }
  406.     bindp[0] = bind;
  407. }
  408.  
  409. /*
  410.  * Remove a bind structure from the dle's dle_bind_list and from the dle
  411.  * hash table. Primarily called by dle_bind_disable.
  412.  */
  413. static void
  414. dle_bind_hash_remove (dle_t * dle, bind_t * bind)
  415. {
  416.     bind_t    * bind1;
  417.     bind_t    ** bindp, * sap_top, * sap_next;
  418.  
  419.     /* Find the structure in the dle's list of all binds. */ 
  420.     for (bindp = (bind_t **)&dle->dle_bind_list; ; bindp = &bind1->bind_next) {
  421.         bind1 = bindp[0];
  422.         if (bind1 == nilp(bind_t))
  423.             return;
  424.         if (bind1 == bind)
  425.             break;
  426.     }
  427.     /* Remove the bind from the dle_bind_list. */
  428.     bindp[0] = bind->bind_next;
  429.     bind->bind_next = nilp(bind_t);
  430.  
  431.     /* Now locate the structure's location in the sap hash table. */
  432.     bindp = dle_bindp_from_flags_and_sap(dle, bind->bind_flags, bind->bind_sap);
  433.      sap_top = bindp[0];
  434.      sap_next = bind->bind_sap_next;
  435.     if (sap_top == bind) {
  436.         bind_t * hash_next = bind->bind_hash_next;
  437.         /*
  438.          * This is the first bind in the hash table for this sap.
  439.          * If there are other binds for this sap, then promote the
  440.          * next one to be the top of the sap chain.
  441.          */
  442.         if (sap_next != nilp(bind_t)) {
  443.             sap_next->bind_hash_next = hash_next;
  444.             hash_next = sap_next;
  445.         }
  446.         /* Get this bind out of the hash chain. */
  447.         bindp[0] = hash_next;
  448.     } else {
  449.         /*
  450.          * There are multiple binds for this sap in the hash chain and
  451.          * we are not the topmost one.  Find our location in the sap
  452.          * chain and remove us from the list.
  453.          */
  454.         while (sap_top->bind_sap_next != bind) {
  455.             sap_top = sap_top->bind_sap_next;
  456.             if (sap_top == nilp(bind_t))
  457.                 return;
  458.         }
  459.         sap_top->bind_sap_next = sap_next;
  460.     }
  461. }
  462.  
  463. /* Process DL_BIND_REQ messages from dle_wput. */
  464. static int
  465. dle_bind_req (queue_t * q, mblk_t * mp)
  466. {
  467.     UInt8            * addr;
  468.     dl_bind_ack_t    * dlba;
  469.     dl_bind_req_t    * dlbr = (dl_bind_req_t *)mp->b_rptr;
  470.     dcl_t            * dcl = (dcl_t *)q->q_ptr;
  471.     UInt32            sap, flags, new_dcl_flags;
  472.     bind_t            * bind;
  473.  
  474.     if (dcl->dcl_state != DL_UNBOUND || (dcl->dcl_flags & F_DCL_PROMISCUOUS_MASK))
  475.         return DL_OUTSTATE;
  476.  
  477.     /* We only support connectionless mode DLPI. */
  478.     if (dlbr->dl_service_mode != DL_CLDLS ||  dlbr->dl_max_conind != 0)
  479.         return DL_UNSUPPORTED;
  480.     
  481.     /*
  482.      * Determine from the sap what type of bind this is: 802.2,
  483.      * Ethertype or IPX.
  484.      */
  485.     sap = dlbr->dl_sap;
  486.     flags = F_BIND_HASH | F_BIND_MATCH_LOCAL;
  487.     new_dcl_flags = 0;
  488.     /* Check for an 802.2 bind first. */
  489.     if (sap <= 0xFE) {
  490.         /*
  491.          * Don't allow binds to 802.2 Group saps.
  492.          * Group saps may only be bound by a DL_SUBSBIND_REQ with
  493.          * DL_PEER_BIND specified.
  494.          */
  495.         if (sap & 0x1)
  496.             return DL_BADADDR;
  497.  
  498.         if (sap == 0xAA) {
  499.             /*
  500.              * A sap of 0xAA means this will be a SNAP stream and
  501.              * there will be a DL_SUBSBIND_REQ message later.  The
  502.              * bind flags here will put the structure into the hash
  503.              * table such that inbound packets will not match. 
  504.              * During DL_SUBSBIND_REQ processing, the bind structure
  505.              * will be located and modified with the SNAP info;
  506.              * then it will be placed back in the hash table such
  507.              * that inbound packets will be properly dispatched.
  508.              */
  509.             flags |= F_BIND_SNAP_PENDING;
  510.         } else
  511.             flags |= F_BIND_802;
  512.  
  513.         if (dlbr->dl_xidtest_flg & DL_AUTO_XID) {
  514.             flags |= F_BIND_AUTO_XID;
  515.             new_dcl_flags |= F_DCL_AUTO_XID;
  516.         }
  517.         if (dlbr->dl_xidtest_flg & DL_AUTO_TEST) {
  518.             flags |= F_BIND_AUTO_TEST;
  519.             new_dcl_flags |= F_DCL_AUTO_TEST;
  520.         }
  521.         new_dcl_flags |= F_DCL_802;
  522.     } else if (sap == 0xFF) {
  523.         flags |= F_BIND_IPX;
  524.         new_dcl_flags |= F_DCL_IPX;
  525.     } else if (sap > kMaxDIXSAP || sap < kMinDIXSAP)
  526.         return DL_BADADDR;
  527.  
  528.     /* Create a new bind structure for this sap. */
  529.     bind = dle_bind_alloc(dcl, sap, flags);
  530.     if (bind == nilp(bind_t))
  531.         return DL_SYSERR;
  532.  
  533.     /*
  534.      * Put the new bind structure in the hash table.  dle_bind_enable will
  535.      * also link the structure into the dle, and call the board's start
  536.      * routine if this is the first bind.
  537.      */
  538.     dle_bind_enable(bind);
  539.  
  540.     /*
  541.      * Save state in the dcl.  The sap and flags are saved so that outbound
  542.      * packets can be properly formatted if the complete sap information is
  543.      * not included in DL_UNITDATA_REQ messages (this happens if the address
  544.      * length is 6, including just the destination Ethernet address).
  545.      */
  546.     dcl->dcl_state = DL_IDLE;
  547.     dcl->dcl_sap = sap;
  548.     dcl->dcl_flags |= new_dcl_flags;
  549.  
  550.     /* Create the DL_BIND_ACK message and pass upstream to the requestor. */
  551.     dlba = (dl_bind_ack_t *)mp->b_rptr;;
  552.     dlba->dl_primitive = DL_BIND_ACK;
  553.     dlba->dl_sap = sap;
  554.     dlba->dl_addr_length = 8;
  555.     dlba->dl_addr_offset = sizeof(dl_bind_ack_t);
  556.     dlba->dl_max_conind = 0;
  557.  
  558.     dlba->dl_xidtest_flg = 0;
  559.     if (flags & F_BIND_AUTO_XID)
  560.         dlba->dl_xidtest_flg |= DL_AUTO_XID;
  561.     if (flags & F_BIND_AUTO_TEST)
  562.         dlba->dl_xidtest_flg |= DL_AUTO_TEST;
  563.  
  564.     addr = (UInt8 *)&dlba[1];
  565.     addr[6] = (sap >> 8);
  566.     addr[7] = sap & 0xFF;
  567.     mp->b_wptr = &addr[8];
  568.     mp->b_datap->db_type = M_PCPROTO;
  569.     bcopy(dcl_to_dle(dcl)->dle_current_addr, addr, 6);
  570.     qreply(q, mp);
  571.     return 0;
  572. }
  573.  
  574. /* STREAMS close entry point called by board-specific close code. */
  575. int
  576. dle_close (queue_t * q)
  577. {
  578.     dcl_t        * dcl = (dcl_t *)q->q_ptr;
  579.     int            err;
  580.     dle_t        * dle;
  581.     dle_addr_t    * dlea;
  582.     int            changes = 0;
  583.  
  584.     if (dcl == nilp(dcl_t))
  585.         return 0;
  586.  
  587.     /*
  588.      * Remove all entries in the bind hash table associated with
  589.      * this stream.
  590.      */
  591.     dle_remove_all_my_binds(dcl);
  592.  
  593.     /*
  594.      * Decrement the reference count on all multicast addresses (or
  595.      * additional physical addresses) associated with this stream.  If
  596.      * there are no other streams using an address, then dle_hw_addr_dec_ref
  597.      * will delete the associated structure kept in the dle_hw_addr_list.
  598.      */
  599.     dle = dcl_to_dle(dcl);
  600.     while ((dlea = dcl->dcl_addr_list) != nilp(dle_addr_t)) {
  601.         dcl->dcl_addr_list = dlea->dlea_next;
  602.         if  (dle_hw_addr_dec_ref(dle, dlea->dlea_addr) == 0)
  603.             changes = 1;
  604.         /* Delete the dcl's copy of the address structure. */
  605.         OTFreeMem(dlea);
  606.     }
  607.     /*
  608.      * Change the chip's address filtering after all possible
  609.      * changes have been made.
  610.      */
  611.     if (changes != 0)
  612.         dle_hw_address_filter_reset(dle);
  613.  
  614.     /* Delete the instance structure for the stream. */
  615.     err = mi_close_comm(&dle->dle_instance_head, q);
  616.  
  617.     /*
  618.      * Decrement the reference count on the shared instance structure for
  619.      * this board/port. This count is maintained, but not currently used
  620.      * for anything significant by the dlpiether shared code.
  621.      */
  622.     dle->dle_refcnt--;
  623.     return err;
  624. }
  625.  
  626. /* Process DL_DISABMULTI_REQ messages for dle_wput. */
  627. static int
  628. dle_disabmulti_req (queue_t * q, mblk_t * mp)
  629. {
  630.     UInt8                * addr;
  631.     dcl_t                * dcl = (dcl_t *)q->q_ptr;
  632.     dl_disabmulti_req_t * dldmr = (dl_disabmulti_req_t *)mp->b_rptr;
  633.     dle_addr_t            * dlea, ** dleap;
  634.     dle_t                * dle;
  635.  
  636.     if (dcl->dcl_state == DL_UNATTACHED)
  637.         return DL_OUTSTATE;
  638.  
  639.     /* Sanity checks on the request. */
  640.     addr = mi_offset_param(mp, dldmr->dl_addr_offset, dldmr->dl_addr_length);
  641.     if (addr == nilp(UInt8) || dldmr->dl_addr_length != 6)
  642.         return DL_BADADDR;
  643.  
  644.     /* Find the dlea structure for the address to be disabled. */
  645.     addr = &mp->b_rptr[dldmr->dl_addr_offset];
  646.     dleap = dle_dleap_from_addr(dcl, addr);
  647.     dlea = dleap[0];
  648.     if (dlea == nilp(dle_addr_t))
  649.         return DL_NOTENAB;
  650.  
  651.     dleap[0] = dlea->dlea_next;
  652.     dle = dcl_to_dle(dcl);
  653.     if (dle_hw_addr_dec_ref(dle, dlea->dlea_addr) == 0) {
  654.         /*
  655.          * If this was the last reference to the address, then allow
  656.          * the hardware to change its address filtering.
  657.          */
  658.         dle_hw_address_filter_reset(dle);
  659.     }
  660.  
  661.     OTFreeMem(dlea);
  662.     return 0;
  663. }
  664.  
  665. /* Process DL_ENABMULTI_REQ messages for dle_wput. */
  666. static int
  667. dle_enabmulti_req (queue_t * q, mblk_t * mp)
  668. {
  669.     UInt8                * addr;
  670.     dcl_t                * dcl = (dcl_t *)q->q_ptr;
  671.     dl_enabmulti_req_t    * dlemr = (dl_enabmulti_req_t *)mp->b_rptr;
  672.     dle_t                * dle;
  673.     dle_addr_t            * dlea, ** dleap;
  674.     UInt32                ref_cnt;
  675.  
  676.     if (dcl->dcl_state == DL_UNATTACHED)
  677.         return DL_OUTSTATE;
  678.  
  679.     addr = &mp->b_rptr[dlemr->dl_addr_offset];
  680.  
  681.     /* Sanity checks on the request message. */
  682.     addr = mi_offset_param(mp, dlemr->dl_addr_offset, dlemr->dl_addr_length);
  683.     if (addr == nilp(UInt8) || dlemr->dl_addr_length != 6 || (addr[0] & 0x1) == 0)
  684.         return DL_BADADDR;
  685.  
  686.     /*
  687.      * Look for this address in the dcl's list of multicast addresses
  688.      * or just get the pointer where we can add a new dlea structure.
  689.      */
  690.     dleap = dle_dleap_from_addr(dcl, addr);
  691.     if (dleap[0] != nilp(dle_addr_t)) {
  692.         /*
  693.          * If this address is already enabled for this stream,
  694.          * then there's nothing more to do here.
  695.          */
  696.         return 0;
  697.     }
  698.  
  699.     /*
  700.      * Create a new dlea structure for this multicast address. The dlea
  701.      * structure is linked onto the dcl's list of enabled addresses.
  702.      * This list allows dle_close to delete all the addresses associated
  703.      * with the dcl when the stream closes.
  704.      */
  705.     dlea = OTAllocMem(sizeof(dle_addr_t));
  706.     if (dlea == nilp(dle_addr_t))
  707.         return DL_TOOMANY;
  708.  
  709.     /*
  710.      * Associate this address with the dle.  dle_hw_addr_inc_ref will
  711.      * either create another new dlea to keep on the dle's address list
  712.      * or it will just increment the reference count of an existing
  713.      * dlea for this address.  This list is passed to the board-specific
  714.      * code for address filtering; it contains all addresses enabled
  715.      * by all streams associated with the device. 
  716.      */
  717.     dle = dcl_to_dle(dcl);
  718.     ref_cnt = dle_hw_addr_inc_ref(dle, addr);
  719.     if (ref_cnt == 0) {
  720.         OTFreeMem(dlea);
  721.         return DL_TOOMANY;
  722.     }
  723.  
  724.     /* Copy the requested multicast address into the dlea. */
  725.     bcopy(addr, dlea->dlea_addr, 6);
  726.  
  727.     /* And link the structure into the dcl list. */
  728.     dlea->dlea_next = nilp(dle_addr_t);
  729.     dleap[0] = dlea;
  730.  
  731.     if (ref_cnt == 1) {
  732.         /*
  733.          * If this is a new address, then allow the hardware
  734.          * to adjust its address filtering.
  735.          */
  736.         dle_hw_address_filter_reset(dle);
  737.     }
  738.     return 0;
  739. }
  740.  
  741. /* Handle DL_GET_STATISTICS_REQ messages from dle_wput. */
  742. static int
  743. dle_get_statistics_req (queue_t * q, mblk_t * mp)
  744. {
  745.     UInt8                    * wptr;
  746.     dcl_t                    * dcl;
  747.     dle_t                    * dle;
  748.     dl_get_statistics_ack_t    * dlsa;
  749.     TOptionHeader            * topt;
  750.  
  751.     dcl = (dcl_t *)q->q_ptr;
  752.     dle = dcl_to_dle(dcl);
  753.  
  754.     mp->b_datap->db_type = M_PCPROTO;
  755.     dlsa = (dl_get_statistics_ack_t *)mp->b_rptr;
  756.     dlsa->dl_primitive = DL_GET_STATISTICS_ACK;
  757.     dlsa->dl_stat_length = sizeof(dle_interface_status_t)
  758.                 + sizeof(dle_ethernet_status_t)
  759.                 + 2 * sizeof(TOptionHeader);
  760.     dlsa->dl_stat_offset = sizeof(dl_get_statistics_ack_t);
  761.  
  762.     wptr = &mp->b_rptr[sizeof(dl_get_statistics_ack_t)];
  763.     topt = (TOptionHeader *)wptr;
  764.     topt->len = sizeof(TOptionHeader) + sizeof(dle->dle_istatus);
  765.     topt->level = DLPI_XTI_LEVEL;
  766.     topt->name = DL_INTERFACE_MIB;
  767.     topt->status = T_SUCCESS;
  768.     wptr += sizeof(TOptionHeader);
  769.     bcopy((char *)&dle->dle_istatus, wptr, sizeof(dle->dle_istatus));
  770.     wptr += sizeof(dle->dle_istatus);
  771.  
  772.     topt = (TOptionHeader *)wptr;
  773.     topt->len = sizeof(TOptionHeader) + sizeof(dle->dle_estatus);
  774.     topt->level = DLPI_XTI_LEVEL;
  775.     topt->name = DL_ETHERNET_MIB;
  776.     topt->status = T_SUCCESS;
  777.     wptr += sizeof(TOptionHeader);
  778.     bcopy((char *)&dle->dle_estatus, wptr, sizeof(dle->dle_estatus));
  779.     wptr += sizeof(dle->dle_estatus);
  780.     mp->b_wptr = wptr;
  781.     qreply(q, mp);
  782.     return 0;
  783. }
  784.  
  785. /*
  786.  * Find the specified address in the list of addresses for this dle and return
  787.  * a pointer to the cell pointing to the appropriate structure.  If the
  788.  * address is not in the list, then the returned pointer points to the location
  789.  * in which a new structure may be added to the list.  This routine is used
  790.  * by dle_hw_addr_inc_ref and dle_hw_addr_dec_ref to add and delete multicast
  791.  * addresses.
  792.  */
  793. static dle_addrx_t **
  794. dle_hw_dleaxp_from_addr (dle_t * dle, UInt8 * addr)
  795. {
  796.     dle_addrx_t    ** dleaxp = (dle_addrx_t **)&dle->dle_hw_addr_list;
  797.     dle_addrx_t    * dleax;
  798.     size_t        u1;
  799.  
  800.     for ( ; (dleax = dleaxp[0]) != nilp(dle_addrx_t); dleaxp = (dle_addrx_t **)&dleax->dleax_next ) {
  801.         UInt8    sum = 0;
  802.         
  803.         for (u1 = 0; u1 < 6; u1++)
  804.             sum |= dleax->dleax_addr[u1] ^ addr[u1];
  805.         if (sum == 0)
  806.             break;
  807.     }
  808.     return dleaxp;
  809. }
  810.  
  811. /*
  812.  * Associate a multicast or physical address with a dle.  If the address
  813.  * is already being used by another stream, then the address' reference
  814.  * count is incremented.  If this is a new address, then a new structure
  815.  * is allocated and added to the dle_hw_addr_list. This routine is called
  816.  * by dle_enabmulti_req.
  817.  */
  818. static UInt32
  819. dle_hw_addr_inc_ref (dle_t * dle, UInt8 * addr)
  820. {
  821.     dle_addrx_t    ** dleaxp;
  822.     dle_addrx_t    * dleax;
  823.  
  824.     dleaxp = dle_hw_dleaxp_from_addr(dle, addr);
  825.     dleax = dleaxp[0];
  826.     if (dleax == nilp(dle_addrx_t)) {
  827.         dleax = OTAllocMem(sizeof(dle_addrx_t));
  828.         if (dleax == nilp(dle_addrx_t))
  829.             return 0;
  830.         bzero(dleax, sizeof(dle_addrx_t));
  831.         bcopy(addr, dleax->dleax_addr, 6);
  832.         dleax->dleax_next = nilp(dle_addr_t);
  833.         dleaxp[0] = dleax;
  834.     }
  835.     return ++dleax->dleax_ref_cnt;
  836. }
  837.  
  838. /*
  839.  * Disassociate a multicast or physical address with a dle. If this is the
  840.  * last reference to the address, then the corresponding structure is removed
  841.  * from dle_hw_addr_list and freed. This routine is called by dle_disabmulti_req.
  842.  */
  843. static UInt32
  844. dle_hw_addr_dec_ref (dle_t * dle, UInt8 * addr)
  845. {
  846.     dle_addrx_t    ** dleaxp = dle_hw_dleaxp_from_addr(dle, addr);
  847.     dle_addrx_t    * dleax = dleaxp[0];
  848.  
  849.     if (dleax == nilp(dle_addrx_t))
  850.         return 0;
  851.     if (dleax->dleax_ref_cnt-- <= 1) {
  852.         dleaxp[0] = (dle_addrx_t *)dleax->dleax_next;
  853.         OTFreeMem(dleax);
  854.         return 0;
  855.     }
  856.     return dleax->dleax_ref_cnt;
  857. }
  858.  
  859. /*
  860.  * Change the address filtering for the board by calling the hardware address
  861.  * filter reset routine.  This routine is called by dle_enabmulti_req,
  862.  * dle_disabmulti_req, dle_bind_enable, and dle_bind_disable.
  863.  */
  864. static void
  865. dle_hw_address_filter_reset (dle_t * dle)
  866. {
  867.     bind_t        * bind;
  868.     size_t        count = 0;
  869.     dle_addrx_t    * dleax;
  870.     size_t        error_count = 0;
  871.  
  872.     dleax = dle->dle_hw_addr_list;
  873.     for ( ; dleax; dleax = (dle_addrx_t *)dleax->dleax_next)
  874.         count++;
  875.     
  876.     for (bind = dle->dle_match_any; bind != nilp(bind_t); bind = bind->bind_next) {
  877.         if (bind->bind_dcl->dcl_flags & F_DCL_WANTS_ERROR_PACKETS) {
  878.             error_count = 1;
  879.             break;
  880.         }
  881.     }
  882.  
  883.     (*dle->dle_hw.dlehw_address_filter_reset)(dle_to_hw(dle)
  884.         , dle->dle_hw_addr_list, count, dle->dle_match_any_count
  885.         , dle->dle_match_any_multicast_count, 1, error_count);
  886. }
  887.  
  888. /* Handle all inbound packets destined for the 802.2 Global sap. */
  889. static void
  890. dle_inbound_802_broadcast (dle_t * dle, mblk_t * mp)
  891. {
  892.     bind_t                * bind;
  893.     dl_unitdata_ind_t    * dlui;
  894.     UInt8                * dst, * hdr;
  895.     mblk_t                * mp1;
  896.     UInt8                sum;
  897.  
  898.     hdr = mp->b_rptr;
  899.     mp->b_rptr += 17;    /* Strip the Ethernet and LLC headers. */
  900.  
  901.     /*
  902.      * We only want to handle these packets if they
  903.      * were sent to our local address or to a
  904.      * broadcast address.  No multicasts.
  905.      */
  906.     {
  907.         UInt8    * addr = dle->dle_current_addr;
  908.         size_t    i1;
  909.         UInt8    sum = 0;
  910.         UInt8    broadcast_sum = 0xFF;
  911.         
  912.         for (i1 = 0; i1 < 6; i1++) {
  913.             sum |= addr[i1] ^ hdr[i1];
  914.             broadcast_sum &= hdr[i1];
  915.         }
  916.         if (sum != 0 && broadcast_sum != 0xff) {
  917.             freemsg(mp);
  918.             return;
  919.         }
  920.     }
  921.  
  922.     /* Make sure we have at least one interested party. */
  923.     bind = dle->dle_bind_list;
  924.     do {
  925.         if ((bind->bind_flags & (F_BIND_802 | F_BIND_SNAP)) == F_BIND_802)
  926.             break;
  927.     } while ((bind = bind->bind_next) != nilp(bind_t));
  928.     if (bind == nilp(bind_t)) {
  929.         freemsg(mp);
  930.         return;
  931.     }
  932.  
  933.     /* Allocate a DL_UNITDATA_IND to pass upstream. */
  934.     mp1 = allocb(sizeof(dl_unitdata_ind_t)+16, BPRI_LO);
  935.     if (mp1 == nilp(mblk_t)) {
  936.         freemsg(mp);
  937.         return;
  938.     }
  939.     mp1->b_cont = mp;
  940.     mp = mp1;
  941.     mp->b_datap->db_type = M_PROTO;
  942.  
  943.     dst = mp->b_rptr;
  944.     dlui = (dl_unitdata_ind_t *)dst;
  945.  
  946.     sum = hdr[0];
  947.     if (sum & 0x1) {
  948.         if ((sum & hdr[1] & hdr[2] & hdr[3] & hdr[4] & hdr[5]) == 0xFF) {
  949.             dle->dle_istatus.broadcast_frames_received++;
  950.             dlui->dl_group_address = keaBroadcast;
  951.         } else {
  952.             dle->dle_istatus.multicast_frames_received++;
  953.             dlui->dl_group_address = keaMulticast;
  954.         }
  955.     } else {
  956.         dlui->dl_group_address = 0;
  957.         dle->dle_istatus.unicast_frames_received++;
  958.     }
  959.  
  960.     dlui->dl_primitive = DL_UNITDATA_IND;
  961.     dlui->dl_dest_addr_length = 8;
  962.     dlui->dl_dest_addr_offset = sizeof(*dlui);
  963.     dlui->dl_src_addr_offset = sizeof(*dlui) + 8;
  964.     dlui->dl_src_addr_length = 8;
  965.  
  966.     dst = (UInt8 *)&dlui[1];
  967.     dst[0] = hdr[0];
  968.     dst[1] = hdr[1];
  969.     dst[2] = hdr[2];
  970.     dst[3] = hdr[3];
  971.     dst[4] = hdr[4];
  972.     dst[5] = hdr[5];
  973.     dst[6] = 0;
  974.     dst[7] = hdr[LLC_DSAP_OFFSET];
  975.     dst += 8;
  976.  
  977.     dst[0] = hdr[6];
  978.     dst[1] = hdr[7];
  979.     dst[2] = hdr[8];
  980.     dst[3] = hdr[9];
  981.     dst[4] = hdr[10];
  982.     dst[5] = hdr[11];
  983.     dst[6] = 0;
  984.     dst[7] = hdr[LLC_SSAP_OFFSET];
  985.  
  986.     dst += 8;
  987.     mp->b_wptr = dst;
  988.  
  989.     do {
  990.         /*
  991.          * Pass broadcast sap packets only to plain 802 bindings,
  992.          * not to SNAP bindings.  We have to check for correct
  993.          * flags from the first bind, since dle_inbound_probe
  994.          * only checks for the first 802 stream and does not
  995.          * qualify on SNAP status.  This allows XID and Test
  996.          * packets to be dispatched properly for the global sap.
  997.          */
  998.         if ((bind->bind_flags & (F_BIND_802 | F_BIND_SNAP)) != F_BIND_802) {
  999.             bind = bind->bind_next;
  1000.             continue;
  1001.         }
  1002.  
  1003.         mp1 = dupmsg(mp);
  1004.         if ( mp1 != nilp(mblk_t) ) {
  1005.             putq(bind->bind_dcl->dcl_rq, mp1);
  1006.         } else {
  1007.             putq(bind->bind_dcl->dcl_rq, mp);
  1008.             mp = nilp(mblk_t);
  1009.             break;
  1010.         }
  1011.     } while ( bind != nilp(bind_t) );
  1012.  
  1013.     if ( mp != nilp(mblk_t) )
  1014.         freemsg(mp);
  1015. }
  1016.  
  1017. void
  1018. dle_inbound (dle_t * dle, mblk_t * mp)
  1019. {
  1020.     UInt8        * rptr = mp->b_rptr;
  1021.     UInt32        hash_sap = (((UInt32)rptr[12]) << 8) | (UInt32)rptr[13];
  1022.     UInt32        ssap;
  1023.     UInt32        dsap;
  1024.     bind_t        * bind;
  1025.     dcl_t        * dcl;
  1026.     UInt32        dest_addr_type;
  1027.     UInt32        flags = 0;
  1028.     UInt32        match_flags = 0;
  1029.     size_t        hdr_len;
  1030.     size_t        i1;
  1031.     size_t        msg_len;
  1032.     mblk_t        * mp1;
  1033.     UInt8        * snap_ptr = nilp(UInt8);
  1034.     UInt8        sum;
  1035.  
  1036.     msg_len = 0;
  1037.     mp1 = mp;
  1038.     do {
  1039.         msg_len += mp1->b_wptr - mp1->b_rptr;
  1040.     } while ( (mp1 = mp1->b_cont) != nilp(mblk_t) );
  1041.  
  1042.     dle->dle_intr_active = true;
  1043.  
  1044.     /* Interface MIB statistics. */
  1045.     dle->dle_istatus.bytes_received += msg_len;
  1046.  
  1047.     dsap = hash_sap;
  1048.     ssap = hash_sap;
  1049.     hdr_len = 14;
  1050.     /* Determine what type of binding we are looking for. */
  1051.     if (hash_sap < kMinDIXSAP) {
  1052.         /*
  1053.          * Make sure that the length in the 802.3 header matches
  1054.          * the number of bytes actually received.  Note that hash_sap
  1055.          * actually holds the length of the packet at this point.
  1056.          */
  1057.         hash_sap += 14;
  1058.         if (hash_sap != msg_len) {
  1059.             int    xtra_bytes;
  1060.             
  1061.             if (hash_sap > msg_len) {
  1062.                 /* Not enough bytes in the message. */
  1063.                 dle_inbound_error(dle, mp, DL_BAD_802_3_LENGTH);
  1064.                 dle->dle_intr_active = 0;
  1065.                 return;
  1066.             }
  1067.             /* Strip extra pad bytes from the end of the packet. */
  1068.             xtra_bytes = msg_len - hash_sap;
  1069.             if (mp->b_cont != nilp(mblk_t))
  1070.                 adjmsg(mp, -xtra_bytes);
  1071.             else
  1072.                 mp->b_wptr -= xtra_bytes;
  1073.             msg_len = hash_sap;
  1074.         }
  1075.  
  1076.         dsap = (UInt32)rptr[LLC_DSAP_OFFSET];
  1077.         ssap = (UInt32)rptr[LLC_SSAP_OFFSET];
  1078.         hash_sap = dsap;
  1079.  
  1080.         /*
  1081.          * If there are two bytes of 0xFF at offsets 14 and 15, then we
  1082.          * have an IPX "raw" packet.  If there is only one byte of 0xFF
  1083.          * at offset 14, then we have a packet destined for the 802
  1084.          * broadcast sap.
  1085.          */
  1086.         if ((dsap & ssap) == 0xff) {
  1087.             flags = F_BIND_IPX;
  1088.             goto check_hash_table;
  1089.         }
  1090.  
  1091.         flags = F_BIND_802;
  1092.         match_flags = F_BIND_MATCH_ANY_802;
  1093.  
  1094.         hdr_len = 17;
  1095.         /* Catch 802.2 Test and XID packets. */
  1096.         if (rptr[LLC_CONTROL_OFFSET] != LLC_DATA_VALUE) {
  1097.             /*
  1098.              * dle_inbound_xidtest will ignore any packets it
  1099.              * is not interested in.
  1100.              */
  1101.             mp1 = dupmsg(mp);
  1102.             if (mp1 != nilp(mblk_t))
  1103.                 dle_inbound_xidtest(dle, mp1);
  1104.             goto check_promiscuous;
  1105.         }
  1106.  
  1107.         switch (dsap) {
  1108.             case 0xAA:
  1109.                 hdr_len = 22;
  1110.                 snap_ptr = &rptr[17];
  1111.                 flags = F_BIND_802 | F_BIND_SNAP;
  1112.                 hash_sap = ((UInt32)rptr[20] << 8) | (UInt32)rptr[21];
  1113.                 break;
  1114.             case 0xFF:
  1115.                 /*
  1116.                  * If there's only one byte of 0xFF, then we
  1117.                  * have a broadcast sap for 802.
  1118.                  */
  1119.                 mp1 = dupmsg(mp);
  1120.                 if (mp1 != nilp(mblk_t))
  1121.                     dle_inbound_802_broadcast(dle, mp);
  1122.                 goto check_promiscuous;
  1123.             default:
  1124.                 break;
  1125.         }
  1126.  
  1127.         /*
  1128.          * Make sure we have at least enough data to hold the headers.
  1129.          * This test must follow the XID/Test checks.
  1130.          */
  1131.         if (msg_len < hdr_len) {
  1132.             freemsg(mp);
  1133.             dle->dle_intr_active = 0;
  1134.             return;
  1135.         }
  1136.     }
  1137.  
  1138. check_hash_table:;
  1139.     /* Find the beginning of the appropriate row in the hash table. */
  1140.     i1 = DLE_SAP_HASH_VALUE(hash_sap, flags);
  1141.     bind = dle->dle_sap_hash_tbl[i1];
  1142.  
  1143.     /* Walk thru all binds in this chain looking for the destination sap. */
  1144.     while (bind != nilp(bind_t)) {
  1145.         if (bind->bind_sap == hash_sap)
  1146.             goto process_packet;
  1147.  
  1148.         /*
  1149.          * We haven't found the sap list yet, so walk along
  1150.          * the hash chain.
  1151.          */
  1152.         bind = bind->bind_hash_next;
  1153.     }
  1154.  
  1155. check_promiscuous:;
  1156.     dle->dle_istatus.receive_unknown_protos++;
  1157.  
  1158.     /*
  1159.      * If we didn't match any specific binds, then check for
  1160.      * promiscuous bindings.
  1161.      */
  1162.     if ((rptr[0] & 0x1) && (bind = dle->dle_match_any_multicast) != nilp(bind_t))
  1163.         goto process_packet;
  1164.  
  1165.     if ((flags & F_BIND_802) && (bind = dle->dle_match_any_802) != nilp(bind_t))
  1166.         goto process_packet;
  1167.  
  1168.     bind = dle->dle_match_any;
  1169.     if (bind == nilp(bind_t)) {
  1170.         freemsg(mp);
  1171.         dle->dle_intr_active = 0;
  1172.         return;
  1173.     }
  1174.  
  1175. process_packet:;
  1176.     mp->b_rptr = &rptr[hdr_len];    /* strip header for M_DATA folk */
  1177.  
  1178.     match_flags |= F_BIND_MATCH_ANY;
  1179.     sum = rptr[0];
  1180.     if (sum & 0x1) {
  1181.         match_flags |= F_BIND_MATCH_ANY_MULTICAST;
  1182.         if ((sum & rptr[1] & rptr[2] & rptr[3] & rptr[4] & rptr[5]) == 0xFF) {
  1183.             dle->dle_istatus.broadcast_frames_received++;
  1184.             dest_addr_type = keaBroadcast;
  1185.         } else {
  1186.             dle->dle_istatus.multicast_frames_received++;
  1187.             dest_addr_type = keaMulticast;
  1188.         }
  1189.     } else {
  1190.         dest_addr_type = 0;
  1191.         dle->dle_istatus.unicast_frames_received++;
  1192.     }
  1193.  
  1194.     /*
  1195.      * Loop through all binds for the target sap, and then loop through
  1196.      * all relevant promiscuous binds.  The packet is delivered to each
  1197.      * interested party.
  1198.      */
  1199.     do {
  1200.         bind_t     * next = bind->bind_sap_next;
  1201.         UInt32    flags = bind->bind_flags;
  1202.  
  1203.         /*
  1204.          * Make sure the destination address is targetted for this
  1205.          * binding.
  1206.          */
  1207.         {
  1208.             /*
  1209.              * Match against our local address before checking for other
  1210.              * multicast addresses that are associated with this stream.
  1211.              */
  1212.             UInt8        * addr = dle->dle_current_addr;
  1213.             dle_addr_t    * dlea = bind->bind_dcl->dcl_addr_list;
  1214.     
  1215.             while (true) {
  1216.                 sum = addr[0] ^ rptr[0];
  1217.                 sum |= addr[1] ^ rptr[1];
  1218.                 sum |= addr[2] ^ rptr[2];
  1219.                 sum |= addr[3] ^ rptr[3];
  1220.                 sum |= addr[4] ^ rptr[4];
  1221.                 sum |= addr[5] ^ rptr[5];
  1222.                 if (sum == 0)
  1223.                     goto find_next;
  1224.                 if (dlea == nilp(dle_addr_t))
  1225.                     break;
  1226.                 addr = dlea->dlea_addr;
  1227.                 dlea = dlea->dlea_next;
  1228.             }
  1229.         }
  1230.  
  1231.         /* If this binding is promiscuous, then deliver the packet. */
  1232.         if (bind->bind_flags & F_BIND_PROMISCUOUS_MASK) {
  1233.             /* Check for binds which only want multicast addresses.*/
  1234.             if ((bind->bind_flags & F_BIND_MATCH_ANY_MULTICAST)
  1235.             &&  (dest_addr_type == 0))
  1236.                 bind = nilp(bind_t);
  1237.         } else if (dest_addr_type != keaBroadcast) {
  1238.             /*
  1239.              * If we didn't find a matching address setting,
  1240.              * then walk to the next bind, if there is one.
  1241.              */
  1242.             bind = nilp(bind_t);
  1243.         }
  1244.  
  1245.     find_next:;
  1246.         match_flags |= (flags & F_BIND_HASH);
  1247.  
  1248.         /*
  1249.          * If we're at the end of binds for this sap or at the end of
  1250.          * processing one of the promiscuous lists, then check for the
  1251.          * next promiscuous list to follow.
  1252.          */
  1253.         if (next == nilp(bind_t)) {
  1254.             if (flags & F_BIND_HASH) {
  1255.                 /*
  1256.                  * If we have a sap match and there are clients
  1257.                  * wanting to see all matched packets, then the
  1258.                  * first promiscuous list to check is
  1259.                  * dle_match_matched.
  1260.                  */
  1261.                 if ((match_flags & F_BIND_HASH)
  1262.                     &&  (next = dle->dle_match_matched) != nilp(bind_t))
  1263.                     goto found_next;
  1264.                 goto check_multicast_promiscuous;
  1265.             }
  1266.  
  1267.             /*
  1268.              * We're already following the promiscuous list,
  1269.              * dle_match_any, so there are no more lists to check
  1270.              * for interested clients.  Note that this check must
  1271.              * follow the check for F_BIND_HASH since both flags
  1272.              * may be set for promiscuous sap bindings.
  1273.              */
  1274.             if (flags & F_BIND_MATCH_ANY)
  1275.                 goto found_next;
  1276.  
  1277.             /*
  1278.              * We're following dle_match_matched list and now we
  1279.              * need to switch to dle_match_any_multicast, if the
  1280.              * destination is a multicast address.
  1281.              */
  1282.             if (flags & F_BIND_MATCH_MATCHED) {
  1283.     check_multicast_promiscuous:;
  1284.                 /*
  1285.                  * If the destination is a multicast address
  1286.                  * and there are promiscuous multicast bound
  1287.                  * clients, then the next list to use is
  1288.                  * dle_match_any_multicast.
  1289.                  */
  1290.                 if ((match_flags & F_BIND_MATCH_ANY_MULTICAST)
  1291.                     &&  (next = dle->dle_match_any_multicast) != nilp(bind_t))
  1292.                     goto found_next;
  1293.                 goto check_802_promiscuous;
  1294.             }
  1295.  
  1296.             /*
  1297.              * We're following dle_match_any_multicast list and
  1298.              * now we need to switch to dle_match_any_802, if this
  1299.              * is an 802 packet.
  1300.              */
  1301.             if (flags & F_BIND_MATCH_ANY_MULTICAST) {
  1302.     check_802_promiscuous:;
  1303.                 /*
  1304.                  * If this is an 802 packet and there are
  1305.                  * promiscuous 802 bound clients (OT private),
  1306.                  * then the next list is dle_match_any_802.
  1307.                  */
  1308.                 if ((match_flags & F_BIND_MATCH_ANY_802)
  1309.                     && (next = dle->dle_match_any_802) != nilp(bind_t))
  1310.                     goto found_next;
  1311.             }
  1312.  
  1313.             /*
  1314.              * If we've checked all other promiscuous lists, then
  1315.              * it's finally time to try the last one for matching
  1316.              * all packets.
  1317.              */
  1318.             next = dle->dle_match_any;
  1319.         }
  1320.     found_next:;
  1321.         if (bind == nilp(bind_t)) {
  1322.             bind = next;
  1323.             continue;
  1324.         }
  1325.  
  1326.         /* Deliver the packet to the client stream of this bind. */
  1327.         dcl = bind->bind_dcl;
  1328.         if (!(dcl->dcl_flags & F_DCL_WANTS_RS_HEADER)
  1329.             && ((match_flags & F_BIND_MATCH_ANY_MULTICAST)
  1330.              | (dcl->dcl_flags & F_DCL_NOT_FAST_PATH))) {
  1331.             if (mp->b_datap->db_type != M_PROTO) {
  1332.                 size_t                addr_len = 8;
  1333.                 dl_unitdata_ind_t    * dlui;
  1334.                 UInt8                * dst, * hdr;
  1335.  
  1336.                 if (snap_ptr != nilp(UInt8))
  1337.                     addr_len = 13;
  1338.                 mp1 = allocb(sizeof(dl_unitdata_ind_t)+(2*addr_len), BPRI_LO);
  1339.                 if (mp1 == nilp(mblk_t)) {
  1340.                     bind = next;
  1341.                     if (bind != nilp(bind_t))
  1342.                         continue;
  1343.                     freemsg(mp);
  1344.                     dle->dle_intr_active = 0;
  1345.                     return;
  1346.                 }
  1347.                 mp1->b_cont = mp;
  1348.                 mp = mp1;
  1349.                 mp->b_datap->db_type = M_PROTO;
  1350.  
  1351.                 dst = mp->b_rptr;
  1352.                 dlui = (dl_unitdata_ind_t *)dst;
  1353.                 dlui->dl_primitive = DL_UNITDATA_IND;
  1354.                 dlui->dl_dest_addr_length = addr_len;
  1355.                 dlui->dl_dest_addr_offset = sizeof(*dlui);
  1356.                 dlui->dl_src_addr_offset = sizeof(*dlui) + addr_len;
  1357.                 dlui->dl_src_addr_length = addr_len;
  1358.  
  1359.                 hdr = rptr;
  1360.                 dlui->dl_group_address = dest_addr_type;
  1361.  
  1362.                 dst = (UInt8 *)&dlui[1];
  1363.                 dst[0] = hdr[0];
  1364.                 dst[1] = hdr[1];
  1365.                 dst[2] = hdr[2];
  1366.                 dst[3] = hdr[3];
  1367.                 dst[4] = hdr[4];
  1368.                 dst[5] = hdr[5];
  1369.                 dst[6] = (UInt8)(dsap >> 8);
  1370.                 dst[7] = (UInt8)dsap;
  1371.                 if (snap_ptr != nilp(UInt8)) {
  1372.                     dst[8] = snap_ptr[0];
  1373.                     dst[9] = snap_ptr[1];
  1374.                     dst[10] = snap_ptr[2];
  1375.                     dst[11] = snap_ptr[3];
  1376.                     dst[12] = snap_ptr[4];
  1377.                 }
  1378.                 dst += addr_len;
  1379.  
  1380.                 dst[0] = hdr[6];
  1381.                 dst[1] = hdr[7];
  1382.                 dst[2] = hdr[8];
  1383.                 dst[3] = hdr[9];
  1384.                 dst[4] = hdr[10];
  1385.                 dst[5] = hdr[11];
  1386.                 dst[6] = (UInt8)(ssap >> 8);
  1387.                 dst[7] = (UInt8)ssap;
  1388.                 if (snap_ptr != nilp(UInt8)) {
  1389.                     dst[8] = snap_ptr[0];
  1390.                     dst[9] = snap_ptr[1];
  1391.                     dst[10] = snap_ptr[2];
  1392.                     dst[11] = snap_ptr[3];
  1393.                     dst[12] = snap_ptr[4];
  1394.                 }
  1395.                 dst += addr_len;
  1396.                 mp->b_wptr = dst;
  1397.             }
  1398.             mp1 = mp;
  1399.             if (next != nilp(bind_t))
  1400.                 mp1 = dupmsg(mp);
  1401.         } else if ( mp->b_datap->db_type == M_PROTO) {
  1402.             if (next != nilp(bind_t)) {
  1403.                 mp1 = dupmsg(mp->b_cont);
  1404.             } else {
  1405.                 mp1 = mp->b_cont;
  1406.                 freeb(mp);
  1407.             }
  1408.         } else {
  1409.             mp1 = mp;
  1410.             if (next)
  1411.                 mp1 = dupmsg(mp);
  1412.         }
  1413.         if (mp1 != nilp(mblk_t)) {
  1414.             if (!(dcl->dcl_flags & F_DCL_WANTS_RS_HEADER)
  1415.             || (mp1 = dle_inbound_special(dcl, mp1, msg_len, rptr, DL_NORMAL_STATUS)) != nilp(mblk_t))
  1416.                 putq(dcl->dcl_rq, mp1);
  1417.         }
  1418.         bind = next;
  1419.     } while (bind != nilp(bind_t));
  1420.  
  1421.     dle->dle_intr_active = 0;
  1422. }
  1423.  
  1424. /*
  1425.  * dle_inbound_error is called from the board-specific receive routine to deliver
  1426.  * a corrupted packet to interested promiscuous streams.  Board code should
  1427.  * only call here after we have passed an error_count > 0 to its address reset
  1428.  * routine.  Nothing bad will happen if this routine is called when there are
  1429.  * no interested streams, but it's a waste of effort.
  1430.  *
  1431.  * dle_inbound also calls this routine when it receives a packet with a too large
  1432.  * 802.3 length (the length in the header is greater than the number of bytes
  1433.  * received.
  1434.  */
  1435. void
  1436. dle_inbound_error (dle_t * dle, mblk_t * mp, unsigned long flags)
  1437. {
  1438.     bind_t            * bind;
  1439.     bind_t            * bind_next;
  1440.     mblk_t            * mp1;
  1441.     unsigned int    msg_len;
  1442.  
  1443.     /* See if any promiscuous bindings want error packets. */
  1444.     for (bind = dle->dle_match_any; ; bind = bind->bind_sap_next) {
  1445.         if (bind == nilp(bind_t)) {
  1446.             freemsg(mp);
  1447.             return;
  1448.         }
  1449.         if (bind->bind_dcl->dcl_flags & F_DCL_WANTS_ERROR_PACKETS)
  1450.             break;
  1451.     }
  1452.  
  1453.     /* Calculate the length of the packet. */
  1454.     msg_len = 0;
  1455.     mp1 = mp;
  1456.     do {
  1457.         msg_len += mp1->b_wptr - mp1->b_rptr;
  1458.     } while ((mp1 = mp1->b_cont) != NULL);
  1459.  
  1460.     flags |= DL_ERROR_STATUS;
  1461.     do {
  1462.         bind_next = bind->bind_sap_next;
  1463.         while (bind_next) {
  1464.             if (bind_next->bind_dcl->dcl_flags & F_DCL_WANTS_ERROR_PACKETS)
  1465.                 break;
  1466.             bind_next = bind_next->bind_sap_next;
  1467.         }
  1468.  
  1469.         /* If there is more than one interested stream, then dup the message. */
  1470.         if (bind_next) {
  1471.             mp1 = dupmsg(mp);
  1472.             if (!mp1) {
  1473.                 bind_next = nilp(bind_t);
  1474.                 mp1 = mp;
  1475.             }
  1476.         } else
  1477.             mp1 = mp;
  1478.  
  1479.         mp1 = dle_inbound_special(bind->bind_dcl, mp1, msg_len, mp1->b_rptr, flags);
  1480.         if (mp1)
  1481.             putq(bind->bind_dcl->dcl_rq, mp1);
  1482.     } while ((bind = bind_next) != NULL);
  1483. }
  1484.  
  1485. /*
  1486.  * dle_inbound_special is called by dle_inbound and dle_inbound_error to prepend
  1487.  * receive status on a packet.  The new message is returned to the caller for
  1488.  * delivery to the client queue.
  1489.  */
  1490. static mblk_t *
  1491. dle_inbound_special (dcl_t * dcl, mblk_t * mp1, size_t msg_len
  1492.             , UInt8 * rptr, UInt32 flags)
  1493. {
  1494.     mblk_t                * mp2;
  1495.     mblk_t                * mp3;
  1496.     dl_recv_status_t    * dlrs;
  1497.  
  1498.     /* Point mp2 at the first M_DATA mblk */
  1499.     mp2 = mp1;
  1500.     if (mp1->b_datap->db_type == M_PROTO)
  1501.         mp2 = mp1->b_cont;
  1502.  
  1503.     /* Restore b_rptr to the beginning of the full packet */
  1504.     mp2->b_rptr = rptr;
  1505.  
  1506.         /*
  1507.          * Allocate a separate block for the receive status.  The message passed in
  1508.          * may be dup'ed, so it is not generally safe to overwrite the status at
  1509.          * the top of the message, even if the space is available.  This code could
  1510.          * probably be made more efficient, but it would be much more complicated.
  1511.          */
  1512.         mp3 = allocb(sizeof(dl_recv_status_t), BPRI_LO);
  1513.         if (mp3 == nilp(mblk_t)) {
  1514.             freemsg(mp1);
  1515.             return nilp(mblk_t);
  1516.         }
  1517.         mp3->b_cont = mp2;
  1518.         if (mp1 == mp2)
  1519.             mp1 = mp3;
  1520.         else
  1521.             mp1->b_cont = mp3;
  1522.         mp2 = mp3;
  1523.         rptr = mp2->b_datap->db_lim;
  1524.         mp2->b_wptr = rptr;
  1525.     
  1526.         rptr -= sizeof(dl_recv_status_t);
  1527.         mp2->b_rptr = rptr;
  1528.         dlrs = (dl_recv_status_t *)rptr;
  1529.         OTGetTimeStamp(&dlrs->dl_timestamp);
  1530.         dlrs->dl_flags = DL_VERSION | flags;
  1531.         dlrs->dl_packet_length_before_truncation = msg_len;
  1532.     
  1533.         /* If the packet is longer than the truncation length, trim it. */
  1534.         if (msg_len > dcl->dcl_truncation_length) {
  1535.             dlrs->dl_flags |= DL_TRUNCATED_PACKET;
  1536.         adjmsg(mp2, dcl->dcl_truncation_length - msg_len);
  1537.         msg_len = dcl->dcl_truncation_length;
  1538.     }
  1539.  
  1540.     msg_len += sizeof(dl_recv_status_t);
  1541.     /* Pad to an eight byte boundary */
  1542.     if (msg_len & 0x7) {
  1543.         int len_needed = 8 - (msg_len & 0x7);
  1544.  
  1545.         /* Find the last mblk, so we can pad it out */
  1546.         for (mp3 = mp2; mp3->b_cont != nilp(mblk_t); mp3 = mp3->b_cont)
  1547.             ;
  1548.  
  1549.         if ((mp3->b_datap->db_lim - mp3->b_wptr) < len_needed) {
  1550.             mp3->b_cont = allocb(len_needed, BPRI_LO);
  1551.             if (mp3->b_cont == nilp(mblk_t)) {
  1552.                 freemsg(mp1);
  1553.                 return nilp(mblk_t);
  1554.             }
  1555.             mp3 = mp3->b_cont;
  1556.         }
  1557.         msg_len += len_needed;
  1558.         while (len_needed-- != 0)
  1559.             *mp3->b_wptr++ = 0;
  1560.     }
  1561.     dlrs->dl_overall_length = msg_len;
  1562.     return mp1;
  1563. }
  1564.  
  1565. /*
  1566.  * Handle incoming 802.2 Test and XID messages from dle_inbound_finish.
  1567.  *
  1568.  * If the message is a command and there are any binds requesting
  1569.  * automatic handling, then we will send one response.  Additionally,
  1570.  * we pass a DL_TEST_IND/DL_XID_IND to each bind not specifying
  1571.  * automatic handling.
  1572.  *
  1573.  * For response messages, we pass a DL_TEST_CON/DL_XID_CON upstream
  1574.  * to all non-automatic binds.  Nothing is done with these packets
  1575.  * for automatic binds.  If there are only automatic binds, then
  1576.  * the packet will be ignored and freed.
  1577.  */
  1578. static void
  1579. dle_inbound_xidtest (dle_t * dle, mblk_t * mp)
  1580. {
  1581.     bind_t        * bind = nilp(bind_t);
  1582.     mblk_t        * dl_mp;
  1583.     mblk_t        * mp1;
  1584.     UInt8        * hdr = mp->b_rptr;
  1585.     size_t        i1;
  1586.     UInt8        dsap;
  1587.     UInt32        match_flags;
  1588.     UInt32        dl_primitive;
  1589.     UInt32        auto_flag;
  1590.     Boolean        responded;
  1591.  
  1592.     /* Make sure we have enough data for the LLC header. */
  1593.     if (mp->b_wptr - hdr < 17) {
  1594.         freemsg(mp);
  1595.         return;
  1596.     }
  1597.  
  1598.     /*
  1599.      * We only want to handle these packets if they
  1600.      * were sent to our local address or to a
  1601.      * broadcast address.  No multicasts.
  1602.      */
  1603.     {
  1604.         UInt8    * addr = dle->dle_current_addr;
  1605.         UInt8    sum = 0;
  1606.         UInt8    broadcast_sum = 0xFF;
  1607.         
  1608.         for (i1 = 0; i1 < 6; i1++) {
  1609.             sum |= addr[i1] ^ hdr[i1];
  1610.             broadcast_sum &= hdr[i1];
  1611.         }
  1612.         if (sum != 0 && broadcast_sum != 0xff) {
  1613.             freemsg(mp);
  1614.             return;
  1615.         }
  1616.     }
  1617.  
  1618.     dsap = hdr[LLC_DSAP_OFFSET];
  1619.     switch (hdr[LLC_CONTROL_OFFSET]) {
  1620.         case LLC_TEST_VALUE:
  1621.         case LLC_TEST_VALUE | LLC_POLL_FINAL_FLAG:
  1622.             if (hdr[LLC_SSAP_OFFSET] & LLC_RESPONSE_BIT)
  1623.                 dl_primitive = DL_TEST_CON;
  1624.             else
  1625.                 dl_primitive = DL_TEST_IND;
  1626.             auto_flag = F_BIND_AUTO_TEST;
  1627.             break;
  1628.             
  1629.         case LLC_XID_VALUE:
  1630.         case LLC_XID_VALUE | LLC_POLL_FINAL_FLAG:
  1631.             if (hdr[LLC_SSAP_OFFSET] & LLC_RESPONSE_BIT)
  1632.                 dl_primitive = DL_XID_CON;
  1633.             else
  1634.                 dl_primitive = DL_XID_IND;
  1635.             auto_flag = F_BIND_AUTO_XID;
  1636.     
  1637.             /*
  1638.              * As per the 802.2 spec, data in the packet is ignored,
  1639.              * and we will only send back 3 bytes in any response.
  1640.              * Note that we do not pass the 3 bytes upstream to the
  1641.              * client.
  1642.              */
  1643.             if (mp->b_cont != nilp(mblk_t)) {
  1644.                 freemsg(mp->b_cont);
  1645.                 mp->b_cont = nilp(mblk_t);
  1646.             }
  1647.             mp->b_wptr = &hdr[17];
  1648.             break;
  1649.             
  1650.         default:
  1651.             freemsg(mp);
  1652.             return;
  1653.     }
  1654.  
  1655.     mp->b_rptr = hdr + 17;    /* Strip Ethernet and LLC headers */
  1656.  
  1657.     bind = dle->dle_bind_list;
  1658.     switch (dsap) {
  1659.         case 0:
  1660.             /* Only take command packets. */
  1661.             if (hdr[LLC_SSAP_OFFSET] & LLC_RESPONSE_BIT)
  1662.                 bind = nilp(bind_t);
  1663.             if (bind != nilp(bind_t)) {
  1664.                 dle_send_xidtest_response(bind, mp);
  1665.                 freemsg(mp);
  1666.                 return;
  1667.             }
  1668.             break;
  1669.             
  1670.         case 0xAA:
  1671.             match_flags = F_BIND_802 | F_BIND_SNAP;
  1672.             break;
  1673.             
  1674.         case 0xFF:
  1675.             match_flags = F_BIND_802;
  1676.             break;
  1677.             
  1678.         default:
  1679.             i1 = DLE_SAP_HASH_VALUE(((UInt32)dsap), F_BIND_802);
  1680.             bind = dle->dle_sap_hash_tbl[i1];
  1681.             match_flags = 0;
  1682.             while (bind != nilp(bind_t)  &&  bind->bind_sap != dsap)
  1683.                 bind = bind->bind_hash_next;
  1684.             break;
  1685.     }
  1686.  
  1687.     if (bind == nilp(bind_t)) {
  1688.         freemsg(mp);
  1689.         return;
  1690.     }
  1691.  
  1692.     responded = 0;
  1693.     dl_mp = nilp(mblk_t);
  1694.  
  1695.     /* Loop through all binds for this sap. */
  1696.     while (bind != nilp(bind_t)) {
  1697.         if ((bind->bind_flags & match_flags) != match_flags)
  1698.             goto next_one;
  1699.  
  1700.         if  (bind->bind_flags & auto_flag ) {
  1701.             /*
  1702.              * If this is a command and we have not done
  1703.              * an automatic response yet, then send back a
  1704.              * response.  If the packet is a response, then
  1705.              * just ignore it.
  1706.              *
  1707.              * For commands sent to the Global/Broadcast sap,
  1708.              * we will respond once for each unique binding.
  1709.              */
  1710.             if (!(hdr[LLC_SSAP_OFFSET] & LLC_RESPONSE_BIT)) {
  1711.                 if (dsap == 0xFF) {
  1712.                     /*
  1713.                      * We only want to respond once for all
  1714.                      * SNAP bindings.
  1715.                      */
  1716.                     if (bind->bind_flags & F_BIND_SNAP) {
  1717.                         if (responded)
  1718.                             goto next_one;
  1719.                         responded = 1;
  1720.                     }
  1721.                     dle_send_xidtest_response(bind, mp);
  1722.                 } else if ( !responded ) {
  1723.                     dle_send_xidtest_response(bind, mp);
  1724.                     responded = 1;
  1725.                 }
  1726.             }
  1727.             goto next_one;
  1728.         }
  1729.  
  1730.         /*
  1731.          * Create a DLPI message block if we have not done so
  1732.          * already.  These messages have the same format with
  1733.          * different dl_primitives; this makes it easy to use
  1734.          * common code for creating them.
  1735.          */
  1736.         if (dl_mp == nilp(mblk_t)) {
  1737.             dl_test_con_t    * dltc;
  1738.             UInt8            * dst;
  1739.  
  1740.             dl_mp = allocb(sizeof(dl_test_con_t) + 16, BPRI_MED);
  1741.             if (dl_mp == nilp(mblk_t)) {
  1742.                 freemsg(mp);
  1743.                 return;
  1744.             }
  1745.             dl_mp->b_datap->db_type = M_PROTO;
  1746.             dst = dl_mp->b_rptr;
  1747.             dl_mp->b_wptr = &dst[sizeof(dl_test_con_t) + 16];
  1748.  
  1749.             dltc = (dl_test_con_t *)dst;
  1750.             dltc->dl_primitive = dl_primitive;
  1751.  
  1752.             if (hdr[LLC_CONTROL_OFFSET] & LLC_POLL_FINAL_FLAG)
  1753.                 dltc->dl_flag = DL_POLL_FINAL;
  1754.             else
  1755.                 dltc->dl_flag = 0;
  1756.             dltc->dl_dest_addr_length = 8;
  1757.             dltc->dl_dest_addr_offset = sizeof(dl_test_con_t);
  1758.             dltc->dl_src_addr_length = 8;
  1759.             dltc->dl_src_addr_offset = sizeof(dl_test_con_t) + 8;
  1760.  
  1761.             dst = (UInt8 *)&dltc[1];
  1762.             dst[0] = hdr[0];
  1763.             dst[1] = hdr[1];
  1764.             dst[2] = hdr[2];
  1765.             dst[3] = hdr[3];
  1766.             dst[4] = hdr[4];
  1767.             dst[5] = hdr[5];
  1768.             dst[6] = 0;
  1769.             dst[7] = dsap;
  1770.  
  1771.             dst[8] = hdr[6];
  1772.             dst[9] = hdr[7];
  1773.             dst[10] = hdr[8];
  1774.             dst[11] = hdr[9];
  1775.             dst[12] = hdr[10];
  1776.             dst[13] = hdr[11];
  1777.             dst[14] = 0;
  1778.             dst[15] = hdr[LLC_SSAP_OFFSET] & ~LLC_RESPONSE_BIT;
  1779.  
  1780.             /*
  1781.              * If there is data in the message, then
  1782.              * pass the M_DATA blocks upstream. Note that this
  1783.              * only happens with Test messages.  Any data in
  1784.              * XID messages has already been stripped.
  1785.              */
  1786.             if (mp->b_rptr != mp->b_wptr)
  1787.                 dl_mp->b_cont = dupmsg(mp);
  1788.             else if (mp->b_cont != nilp(mblk_t))
  1789.                 dl_mp->b_cont = dupmsg(mp->b_cont);
  1790.         }
  1791.  
  1792.         mp1 = dupmsg(dl_mp);
  1793.         if (mp1 == nilp(mblk_t)) {
  1794.             mp1 = dl_mp;
  1795.             dl_mp = nilp(mblk_t);
  1796.         }
  1797.         putq(bind->bind_dcl->dcl_rq, mp1);
  1798.  
  1799.     next_one:;
  1800.         if (match_flags == 0)
  1801.             bind = bind->bind_sap_next;
  1802.         else
  1803.             bind = bind->bind_next;
  1804.     }
  1805.  
  1806.     /* If there is a dangling dupmsg, then free the extra message. */
  1807.     if (dl_mp != nilp(mblk_t))
  1808.         freemsg(dl_mp);
  1809.     freemsg(mp);
  1810. }
  1811.  
  1812. /* Handle DL_INFO_REQ messages for dle_wput. */
  1813. static int
  1814. dle_info_req (queue_t * q, mblk_t * mp)
  1815. {
  1816.     dl_info_ack_t    * dlia = (dl_info_ack_t *)mp->b_rptr;
  1817.     dcl_t            * dcl = (dcl_t *)q->q_ptr;
  1818.     dle_t            * dle = dcl_to_dle(dcl);
  1819.     UInt8            * dst;
  1820.  
  1821.     /* Make sure any fields we don't know about are zero'ed. */
  1822.     bzero((UInt8 *)dlia, sizeof(dl_info_ack_t));
  1823.  
  1824.     mp->b_datap->db_type = M_PCPROTO;
  1825.     dlia->dl_primitive = DL_INFO_ACK;
  1826.  
  1827.     /*
  1828.      * Maximum packet size, including headers.  The appropriate header
  1829.      * length is subtracted below, depending on how the stream is bound.
  1830.      */
  1831.     dlia->dl_max_sdu = dle->dle_istatus.mtu;
  1832.     dlia->dl_min_sdu = dle->dle_min_sdu;
  1833.  
  1834.     dlia->dl_service_mode = DL_CLDLS;
  1835.     dlia->dl_provider_style = DL_STYLE1;
  1836.     dlia->dl_version = DL_VERSION_2;
  1837.     dlia->dl_current_state = dcl->dcl_state;
  1838.     dlia->dl_mac_type = dcl->dcl_mac_type;
  1839.  
  1840.     /*
  1841.      * Return the current Ethernet address. If we're not bound, then DLPI
  1842.      * says that we should return dl_addr_length 0; however, this tends
  1843.      * to mess up protocols, so we always return the Ethernet address.
  1844.      */
  1845.     dlia->dl_addr_offset = sizeof(dl_info_ack_t);
  1846.     dst = (UInt8 *)&dlia[1];
  1847.     bcopy(dle->dle_current_addr, dst, 6);
  1848.  
  1849.     if (dlia->dl_current_state == DL_IDLE) {
  1850.         /*
  1851.          * If we're bound, then return the sap information.
  1852.          * Sap length is -2 after bind, -7 after subsequent bind.
  1853.          */
  1854.         if (dcl->dcl_flags & F_DCL_SNAP) {
  1855.             dlia->dl_sap_length = -7;    /* must be -7 */
  1856.             dlia->dl_addr_length = 13;    /* must be 13 */
  1857.             dst[6] = 0xaa;
  1858.             dst[7] = 0xaa;
  1859.             bcopy(dcl->dcl_snap, &dst[8], 5);
  1860.             dlia->dl_max_sdu -= 22;        /* Full SNAP header */
  1861.         } else {
  1862.             dlia->dl_sap_length = -2;
  1863.             dlia->dl_addr_length = 8;
  1864.             dst[6] = dcl->dcl_sap >> 8;
  1865.             dst[7] = dcl->dcl_sap & 0xff;
  1866.             if (dcl->dcl_flags & F_DCL_802)
  1867.                 dlia->dl_max_sdu -= 17;    /* 802 header size */
  1868.             else
  1869.                 dlia->dl_max_sdu -= 14;    /* Ethernet header size*/
  1870.         }
  1871.     } else {
  1872.         /* If we're not bound, then just return the Ethernet address. */
  1873.         dlia->dl_sap_length = 0;
  1874.         dlia->dl_addr_length = 6;
  1875.         dlia->dl_max_sdu -= 14;        /* Default header size */
  1876.     }
  1877.  
  1878.     dst += dlia->dl_addr_length;
  1879.     dlia->dl_brdcst_addr_offset = sizeof(dl_info_ack_t) + dlia->dl_addr_length;
  1880.     dlia->dl_brdcst_addr_length = 6;
  1881.     dst[0] = 0xFF;
  1882.     dst[1] = 0xFF;
  1883.     dst[2] = 0xFF;
  1884.     dst[3] = 0xFF;
  1885.     dst[4] = 0xFF;
  1886.     dst[5] = 0xFF;
  1887.     mp->b_wptr = &dst[6];    /* past broadcast address */
  1888.  
  1889.     qreply(q, mp);
  1890.     return 0;
  1891. }
  1892.  
  1893. /*
  1894.  * Make a new board available to the dlpiether common code.  This routine is
  1895.  * called by the board-specific code during initialization; the dle may be
  1896.  * allocated either statically or dynamically by the board code.  After
  1897.  * dle_init, streams for the specified board may be opened by applications.
  1898.  */
  1899. void
  1900. dle_init (dle_t * dle, size_t xtra_hdr_len)
  1901. {
  1902.     /*
  1903.      * Initialize the static parts of the interface statistics and dle
  1904.      * information.  The board code can override these values if necessary.
  1905.      */
  1906.     dle->dle_istatus.speed = 10000000;    /* in bits per second */
  1907.  
  1908.     /*
  1909.      * Set the max transmit size to Ethernet default, including headers.
  1910.      * dle_info_req subtracts the appropriate header length before telling
  1911.      * upstream clients what size they may use.  For "normal" Ethernet,
  1912.      * the reported size is 1500, for 802.2 SNAP, the size is 1492.
  1913.      */
  1914.     dle->dle_istatus.mtu = 1514;
  1915.  
  1916.     /* The min transmit size is 0 since we can pad to the real 60-byte min. */
  1917.     dle->dle_min_sdu = 0;
  1918.  
  1919.     dle->dle_xtra_hdr_len = xtra_hdr_len;
  1920. }
  1921.  
  1922. /*
  1923.  * Find the specified address in the list of addresses for this dcl and return
  1924.  * a pointer to the link pointing to the appropriate structure.  If the
  1925.  * address is not in the list, then the returned pointer points to the location
  1926.  * in which a new structure may be added to the list.  This routine is used
  1927.  * by dle_enabmulti_req and dle_disabmulti_req to add and delete multicast
  1928.  * addresses.
  1929.  */
  1930. static dle_addr_t **
  1931. dle_dleap_from_addr (dcl_t * dcl, UInt8 * addr)
  1932. {
  1933.     dle_addr_t ** dleap = (dle_addr_t **)&dcl->dcl_addr_list;
  1934.     dle_addr_t * dlea;
  1935.  
  1936.     for ( ; (dlea = dleap[0]) != nilp(dle_addr_t); dleap = &dlea->dlea_next) {
  1937.         UInt8    sum = 0;
  1938.         size_t    u1;
  1939.         for (u1 = 0; u1 < 6; u1++)
  1940.             sum |= dlea->dlea_addr[u1] ^ addr[u1];
  1941.         if (sum == 0)
  1942.             break;
  1943.     }
  1944.     return dleap;
  1945. }
  1946.  
  1947. /*
  1948.  * STREAMS open entry point.  This routine is called by the board-specific open
  1949.  * code to initialize the necessary structures.
  1950.  */
  1951. int
  1952. dle_open (dle_t * dle, queue_t * q, dev_t * devp, int flag, int sflag
  1953.         , cred_t * credp, size_t dcl_len)
  1954. {
  1955.     dcl_t    * dcl;
  1956.     int        err;
  1957.  
  1958.     /* If this is a reopen, then there's nothing to do. */
  1959.     if (q->q_ptr != NULL) {
  1960.         mi_qprocson(q);
  1961.         return 0;
  1962.     }
  1963.  
  1964.     err = mi_open_comm(&dle->dle_instance_head, dcl_len, q, devp, flag, sflag, credp);
  1965.     if (err != 0)
  1966.         return err;
  1967.  
  1968.     dcl = (dcl_t *)q->q_ptr;
  1969.     dcl->dcl_hw = dle;
  1970.     dcl->dcl_rq = q;
  1971.     dcl->dcl_state = DL_UNBOUND;
  1972.     dcl->dcl_mac_type = DL_ETHER;
  1973.     dcl->dcl_flags = F_DCL_NOT_FAST_PATH;
  1974.     dle->dle_refcnt++;
  1975.     return 0;
  1976. }
  1977.  
  1978. /* Handle DL_PHYS_ADDR_REQ messages from dle_wput. */
  1979. static int
  1980. dle_phys_addr_req (queue_t * q, mblk_t * mp)
  1981. {
  1982.     UInt8                * rptr = mp->b_rptr;
  1983.     UInt8                * addr;
  1984.     dl_phys_addr_req_t    * dpar;
  1985.     dl_phys_addr_ack_t    * dpaa;
  1986.     dle_t                * dle;
  1987.  
  1988.     rptr = mp->b_rptr;
  1989.     dpar = (dl_phys_addr_req_t *)rptr;
  1990.     dle = dcl_to_dle((dcl_t *)q->q_ptr);
  1991.     switch (dpar->dl_addr_type) {
  1992.         case DL_CURR_PHYS_ADDR:
  1993.             addr = &dle->dle_current_addr[0];
  1994.             break;
  1995.         case DL_FACT_PHYS_ADDR:
  1996.             addr = &dle->dle_factory_addr[0];
  1997.             break;
  1998.         default:
  1999.             return DL_BADPRIM;
  2000.     }
  2001.     dpaa = (dl_phys_addr_ack_t *)rptr;
  2002.     dpaa->dl_primitive = DL_PHYS_ADDR_ACK;
  2003.     dpaa->dl_addr_length = 6;
  2004.     dpaa->dl_addr_offset = sizeof(*dpaa);
  2005.     mp->b_wptr = &rptr[sizeof(*dpaa) + 6];
  2006.     mp->b_datap->db_type = M_PCPROTO;
  2007.     bcopy(addr, &rptr[sizeof(*dpaa)], 6);
  2008.     qreply(q, mp);
  2009.     return 0;
  2010. }
  2011.  
  2012. /* Process DL_PROMISCOFF_REQ messages for dle_wput. */
  2013. static int
  2014. dle_promiscoff_req (queue_t * q, mblk_t * mp)
  2015. {
  2016.     bind_t                * bind;
  2017.     dcl_t                * dcl;
  2018.     dle_t                * dle;
  2019.     UInt32                flags;
  2020.     UInt8                * rptr = mp->b_rptr;
  2021.     dl_promiscoff_req_t * dlpr;
  2022.  
  2023.     dcl = (dcl_t *)q->q_ptr;
  2024.     dle = dcl_to_dle(dcl);
  2025.     dlpr = (dl_promiscoff_req_t *)rptr;
  2026.     switch (dlpr->dl_level) {
  2027.         case DL_PROMISC_PHYS:
  2028.             if (!(dcl->dcl_flags & F_DCL_PROMISC_PHYS))
  2029.                 return 0;
  2030.     
  2031.             /*
  2032.              * If the stream is bound, then undo the promiscuous bits
  2033.              * on its binds.
  2034.              */
  2035.             if (dcl->dcl_state == DL_IDLE) {
  2036.                 bind = (bind_t *)dle->dle_bind_list;
  2037.                 while (bind != nilp(bind_t)) {
  2038.                     if (bind->bind_dcl == dcl  && (bind->bind_flags & F_BIND_MATCH_ANY)) {
  2039.                         bind->bind_flags &= ~F_BIND_MATCH_ANY;
  2040.                         dle->dle_match_any_count--;
  2041.                     }
  2042.                     bind = bind->bind_next;
  2043.                 }
  2044.     
  2045.                 /* Set the hardware into the proper state. */
  2046.                 if (dle->dle_match_any_count == 0) {
  2047.                     dle_hw_address_filter_reset(dle);
  2048.                 }
  2049.             } else {
  2050.                 flags = F_BIND_MATCH_ANY;
  2051.             }
  2052.             
  2053.             dcl->dcl_flags ^= F_DCL_PROMISC_PHYS;
  2054.             break;
  2055.         case DL_PROMISC_MULTI:
  2056.             if (!(dcl->dcl_flags & F_DCL_PROMISC_MULTI))
  2057.                 return 0;
  2058.     
  2059.             /*
  2060.              * If the stream is bound, then undo the promiscuous bits
  2061.              * on its binds.
  2062.              */
  2063.             if (dcl->dcl_state == DL_IDLE) {
  2064.                 bind = (bind_t *)dle->dle_bind_list;
  2065.                 while (bind != nilp(bind_t)) {
  2066.                     if (bind->bind_dcl == dcl && (bind->bind_flags & F_BIND_MATCH_ANY_MULTICAST)) {
  2067.                         bind->bind_flags &= ~F_BIND_MATCH_ANY_MULTICAST;
  2068.                         dle->dle_match_any_multicast_count--;
  2069.                     }
  2070.                     bind = bind->bind_next;
  2071.                 }
  2072.     
  2073.                 /* Set the hardware into the proper state. */
  2074.                 if (dle->dle_match_any_multicast_count == 0) {
  2075.                     dle_hw_address_filter_reset(dle);
  2076.                 }
  2077.             } else 
  2078.                 flags = F_BIND_MATCH_ANY_MULTICAST;
  2079.     
  2080.             dcl->dcl_flags ^= F_DCL_PROMISC_MULTI;
  2081.             break;
  2082.         case DL_PROMISC_SAP:
  2083.             if (!(dcl->dcl_flags & F_DCL_PROMISC_SAP))
  2084.                 return 0;
  2085.     
  2086.             dcl->dcl_flags ^= F_DCL_PROMISC_SAP;
  2087.             flags = F_BIND_MATCH_MATCHED;
  2088.             break;
  2089.     }
  2090.  
  2091.     if (dcl->dcl_state != DL_IDLE) {
  2092.             /* Find the bind structure in the binding lists and remove it. */
  2093.         bind = dle_bind_from_stuff(dcl, flags, dcl->dcl_sap);
  2094.         if (bind != nilp(bind_t)) {
  2095.             dle_bind_disable(dle, bind);
  2096.             dle_bind_free(dle, bind);
  2097.         }
  2098.     }
  2099.     /*
  2100.      * Flush all inbound messages pending on the stream.  It is important
  2101.      * that this message go upstream before the DL_OK_ACK.
  2102.      */
  2103.     flushq(RD(q), FLUSHDATA);
  2104.     putnextctl1(RD(q), M_FLUSH, FLUSHR);
  2105.     return 0;
  2106. }
  2107.  
  2108. /* Process DL_PROMISCON_REQ messages for dle_wput. */
  2109. static int
  2110. dle_promiscon_req (queue_t * q, mblk_t * mp)
  2111. {
  2112.     bind_t                * bind;
  2113.     dcl_t                * dcl;
  2114.     dle_t                * dle;
  2115.     UInt32                flags;
  2116.     UInt8                * rptr = mp->b_rptr;
  2117.     dl_promiscon_req_t    * dlpr;
  2118.     UInt32                sap;
  2119.  
  2120.     dcl = (dcl_t *)q->q_ptr;
  2121.     dle = dcl_to_dle(dcl);
  2122.  
  2123.     dlpr = (dl_promiscon_req_t *)rptr;
  2124.     sap = ~0;
  2125.     if (dcl->dcl_state == DL_IDLE)
  2126.         sap = dcl->dcl_sap;
  2127.  
  2128.     switch (dlpr->dl_level) {
  2129.         case DL_PROMISC_PHYS:
  2130.             if (dcl->dcl_flags & F_DCL_PROMISC_PHYS)
  2131.                 return 0;
  2132.     
  2133.             /*
  2134.              * If the stream is bound to a sap, then this new bind
  2135.              * is promiscuous only for saps already bound to the
  2136.              * stream, whether bound by a DL_BIND_REQ or DL_SUBS_BIND_REQ
  2137.              * with DL_PEER_BIND.  Inbound packets will be dispatched
  2138.              * with the normal hash mechanisms in dle_inbound_probe
  2139.              * and dle_inbound_finish, but the destination address will
  2140.              * not be checked.  If an affected sap is unbound before
  2141.              * this setting is disabled, dle_bind_disable take the right
  2142.              * steps to undo the hardware effects.
  2143.              */
  2144.             if (dcl->dcl_state == DL_IDLE)  {
  2145.                 UInt32    prev_count = dle->dle_match_any_count;
  2146.                 
  2147.                 bind = (bind_t *)dle->dle_bind_list;
  2148.                 while (bind != nilp(bind_t)) {
  2149.                     if (bind->bind_dcl == dcl) {
  2150.                         bind->bind_flags |= F_BIND_MATCH_ANY;
  2151.                         dle->dle_match_any_count++;
  2152.                     }
  2153.                     bind = bind->bind_next;
  2154.                 }
  2155.     
  2156.                 /* Set the hardware into the proper state. */
  2157.                 if (prev_count == 0 &&  dle->dle_match_any_count > 0) {
  2158.                     dle_hw_address_filter_reset(dle);
  2159.                 }
  2160.             } else {
  2161.                 flags = F_BIND_MATCH_ANY;
  2162.             }
  2163.             break;
  2164.             
  2165.         case DL_PROMISC_SAP:
  2166.             if (dcl->dcl_flags & F_DCL_PROMISC_SAP)
  2167.                 return 0;
  2168.     
  2169.             /*
  2170.              * If we're already bound, then this request says we want all
  2171.              * packets for this sap on this machine.  There's nothing
  2172.              * more to do.
  2173.              */
  2174.             if (dcl->dcl_state == DL_IDLE)
  2175.                 return 0;
  2176.     
  2177.             flags = F_BIND_MATCH_MATCHED;
  2178.             break;
  2179.         case DL_PROMISC_MULTI:
  2180.             if (dcl->dcl_flags & F_DCL_PROMISC_MULTI)
  2181.                 return 0;
  2182.     
  2183.             /*
  2184.              * If the stream is bound to a sap, then this new bind
  2185.              * is promiscuous only for saps already bound to the
  2186.              * stream, whether bound by a DL_BIND_REQ or DL_SUBS_BIND_REQ
  2187.              * with DL_PEER_BIND.
  2188.              */
  2189.             if (dcl->dcl_state == DL_IDLE) {
  2190.                 UInt32    prev_count = dle->dle_match_any_multicast_count;
  2191.                 
  2192.                 bind = (bind_t *)dle->dle_bind_list;
  2193.                 while (bind != nilp(bind_t)) {
  2194.                     if (bind->bind_dcl == dcl) {
  2195.                         bind->bind_flags |= F_BIND_MATCH_ANY_MULTICAST;
  2196.                         dle->dle_match_any_multicast_count++;
  2197.                     }
  2198.                     bind = bind->bind_next;
  2199.                 }
  2200.     
  2201.                 /* Set the hardware into the proper state. */
  2202.                 if (prev_count == 0 && dle->dle_match_any_multicast_count > 0) {
  2203.                     dle_hw_address_filter_reset(dle);
  2204.                 }
  2205.             } else
  2206.                 flags = F_BIND_MATCH_ANY_MULTICAST;
  2207.             break;
  2208.         default:
  2209.             return DL_BADPRIM;
  2210.     }
  2211.  
  2212.     if (dcl->dcl_state != DL_IDLE) {
  2213.         /*
  2214.          * If we're not bound to a particular sap, then we need
  2215.          * to create a new binding in one of the promiscuous lists.
  2216.          */
  2217.         bind = dle_bind_alloc(dcl, sap, flags);
  2218.         if (bind == nilp(bind_t))
  2219.             return DL_SYSERR;
  2220.         dle_bind_enable(bind);
  2221.     }
  2222.  
  2223.     switch (dlpr->dl_level) {
  2224.         case DL_PROMISC_PHYS:
  2225.             dcl->dcl_flags |= F_DCL_PROMISC_PHYS;
  2226.             break;
  2227.         case DL_PROMISC_MULTI:
  2228.             dcl->dcl_flags |= F_DCL_PROMISC_MULTI;
  2229.             break;
  2230.         case DL_PROMISC_SAP:
  2231.             dcl->dcl_flags |= F_DCL_PROMISC_SAP;
  2232.             break;
  2233.     }
  2234.     return 0;
  2235. }
  2236.  
  2237. /*
  2238.  * Remove all binds for a stream (dcl).  This routine is called by
  2239.  * dle_unbind_req and dle_close.
  2240.  */
  2241. static void
  2242. dle_remove_all_my_binds (dcl_t * dcl)
  2243. {
  2244.     dle_t    * dle = dcl_to_dle(dcl);
  2245.     bind_t    * bind;
  2246.     bind_t    ** bindp;
  2247.  
  2248.     /*
  2249.      * Walk through the list of all binds for the dle and delete all
  2250.      * those associated with dcl.
  2251.      */
  2252.     for (bindp = (bind_t **)&dle->dle_bind_list; (bind = bindp[0]) != nilp(bind_t); ) {
  2253.         if  (bind->bind_dcl == dcl) {
  2254.             dle_bind_disable(dle, bind);
  2255.             dle_bind_free(dle, bind);
  2256.         } else {
  2257.             bindp = &bind->bind_next;
  2258.         }
  2259.     }
  2260.     dcl->dcl_flags &= ~(F_DCL_PROMISC_PHYS | F_DCL_PROMISC_MULTI
  2261.         | F_DCL_PROMISC_SAP | F_DCL_IPX | F_DCL_SNAP | F_DCL_802);
  2262. }
  2263.  
  2264. void
  2265. dle_rsrv_ctl (queue_t * q, mblk_t * mp)
  2266. {
  2267.     mp->b_datap->db_type = M_DATA;
  2268.     put(WR(q), mp);
  2269. }
  2270.  
  2271. /*
  2272.  * Send an 802.2 LLC Test or XID response message in reply
  2273.  * to an inbound command packet.
  2274.  */
  2275. static void
  2276. dle_send_xidtest_response (bind_t * bind, mblk_t * mp)
  2277. {
  2278.     dle_t    * dle;
  2279.     mblk_t    * mp1;
  2280.     UInt8    * rptr;
  2281.     UInt8    * src;
  2282.     UInt8    dsap;
  2283.  
  2284.     /*
  2285.      * We have to create our own copy of the message since we're
  2286.      * to change the contents of the packet and pass it to the
  2287.      * transmit code.
  2288.      */
  2289.     mp->b_rptr -= 17;    /* Reclaim the stripped headers. */
  2290.     rptr = mp->b_rptr;
  2291.     if ((rptr[LLC_CONTROL_OFFSET] & LLC_XID_VALUE) == LLC_XID_VALUE) {
  2292.         if ((mp->b_datap->db_lim - mp->b_wptr) < 3) {
  2293.             mp1 = allocb(20, BPRI_HI);
  2294.             if (mp1 != nilp(mblk_t)) {
  2295.                 bcopy(rptr, mp1->b_rptr, 17);
  2296.                 mp1->b_wptr = mp1->b_rptr + 17;
  2297.             }
  2298.         } else
  2299.             mp1 = copyb(mp);
  2300.     } else {
  2301.         mp1 = copyb(mp);
  2302.     }
  2303.     mp->b_rptr += 17;    /* Return the original mp unchanged. */
  2304.     if (mp1 == nilp(mblk_t))
  2305.         return;
  2306.  
  2307.     if (mp->b_cont != nilp(mblk_t)) {
  2308.         /*
  2309.          * We only have to get new references to additional
  2310.          * blocks since we're not going to alter them.
  2311.          */
  2312.         mp1->b_cont = dupmsg(mp->b_cont);
  2313.         if (mp1->b_cont == nilp(mblk_t)) {
  2314.             freeb(mp1);
  2315.             return;
  2316.         }
  2317.     }
  2318.  
  2319.     mp = mp1;
  2320.     rptr = mp->b_rptr;
  2321.     mp->b_datap->db_type = M_CTL;    /* Special type for board rsrv */
  2322.     /* Set the destination address from the source address. */
  2323.     rptr[0] = rptr[6];
  2324.     rptr[1] = rptr[7];
  2325.     rptr[2] = rptr[8];
  2326.     rptr[3] = rptr[9];
  2327.     rptr[4] = rptr[10];
  2328.     rptr[5] = rptr[11];
  2329.  
  2330.     /* Set the source address. */
  2331.     dle = dcl_to_dle(bind->bind_dcl);
  2332.     src = dle->dle_current_addr;
  2333.     rptr[6] = src[0];
  2334.     rptr[7] = src[1];
  2335.     rptr[8] = src[2];
  2336.     rptr[9] = src[3];
  2337.     rptr[10] = src[4];
  2338.     rptr[11] = src[5];
  2339.  
  2340.     /*
  2341.      * Set the length field to 0 so it will be assigned correctly
  2342.      * by the board transmit code.
  2343.      */
  2344.     rptr[12] = 0;
  2345.     rptr[13] = 0;
  2346.  
  2347.     /*
  2348.      * Assign the DSAP field from the SSAP.  The new SSAP field is our
  2349.      * bound sap which is guaranteed not to be a 802.2 Group sap.
  2350.      */
  2351.     dsap = rptr[LLC_DSAP_OFFSET];
  2352.     rptr[LLC_DSAP_OFFSET] = rptr[LLC_SSAP_OFFSET];
  2353.  
  2354.     if (dsap != 0) {    
  2355.         if (bind->bind_flags & F_BIND_SNAP)
  2356.             rptr[LLC_SSAP_OFFSET] = 0xAA;
  2357.         else
  2358.             rptr[LLC_SSAP_OFFSET] = bind->bind_dcl->dcl_sap;
  2359.     } else
  2360.         rptr[LLC_SSAP_OFFSET] = 0;
  2361.  
  2362.     /* Turn on the response bit. */
  2363.     rptr[LLC_SSAP_OFFSET] |= LLC_RESPONSE_BIT;
  2364.  
  2365.     /* If this is an XID packet, set the necessary reply fields. */
  2366.     if ((rptr[LLC_CONTROL_OFFSET] & LLC_XID_VALUE) == LLC_XID_VALUE) {
  2367.         /* Set the XID fields. */
  2368.         rptr[17] = XID_FORMAT_IDENTIFIER;
  2369.         rptr[18] = 0x2;        /* Type 2 LLC, non-NULL LSAP */
  2370.         rptr[19] = 0;
  2371.         mp->b_wptr = &rptr[20];
  2372.     }
  2373.  
  2374.     /* Use the read queue of this bind to transmit the packet. */
  2375.     putq(bind->bind_dcl->dcl_rq, mp);
  2376. }
  2377.  
  2378. /* Process DL_SUBSBIND_REQ messages from dle_wput. */
  2379. static int
  2380. dle_subs_bind_req (queue_t * q, mblk_t * mp)
  2381. {
  2382.     UInt8                * addr;
  2383.     dl_subs_bind_ack_t    * dlsba;
  2384.     dl_subs_bind_req_t    * dlsbr = (dl_subs_bind_req_t *)mp->b_rptr;
  2385.     dcl_t                * dcl = (dcl_t *)q->q_ptr;
  2386.     UInt32                flags;
  2387.     bind_t                * bind;
  2388.     UInt32                sap;
  2389.     UInt8                * snap_ptr;
  2390.     SInt32                len;            /* %%% Why signed?? */
  2391.  
  2392.     /* Make sure the stream is bound before allowing any subsequent binds. */
  2393.     if (dcl->dcl_state != DL_IDLE)
  2394.         return DL_OUTSTATE;
  2395.  
  2396.     len = dlsbr->dl_subs_sap_length;
  2397.     snap_ptr = mi_offset_param(mp, dlsbr->dl_subs_sap_offset, len);
  2398.     if (snap_ptr == nilp(UInt8))
  2399.         return DL_BADADDR;
  2400.  
  2401.     switch (dlsbr->dl_subs_bind_class) {
  2402.         case DL_HIERARCHICAL_BIND:
  2403.             /*
  2404.              * Hierarchical binds are only allowed on streams bound to the
  2405.              * SNAP sap (0xAA).  Also, we only allow one subsbind per
  2406.              * stream.  This lookup finds the bind structure allocated by
  2407.              * the previous DL_BIND_REQ.
  2408.              */
  2409.             flags = F_BIND_SNAP_PENDING | F_BIND_HASH;
  2410.             bind = dle_bind_from_stuff(dcl, flags, 0xAA);
  2411.             if (bind == nilp(bind_t))
  2412.                 return DL_OUTSTATE;
  2413.     
  2414.             /* The requested value must contain 5 bytes of SNAP stuff. */
  2415.             if (len != 5)
  2416.                 return DL_BADADDR;
  2417.         
  2418.             sap = (((UInt32)snap_ptr[3]) << 8) | (UInt32)snap_ptr[4];
  2419.     
  2420.             /*
  2421.              * Remove the bind structure from its temporary location
  2422.              * in the hash table.
  2423.              */
  2424.             dle_bind_hash_remove(dcl_to_dle(dcl), bind);
  2425.     
  2426.             /* Fix the bind structure to have its permanent information. */
  2427.             bind->bind_flags &= ~F_BIND_SNAP_PENDING;
  2428.             bind->bind_flags |= F_BIND_SNAP | F_BIND_802 | F_BIND_MATCH_LOCAL;
  2429.             bind->bind_sap = sap;
  2430.             dcl->dcl_sap = sap;
  2431.             dcl->dcl_flags |= F_DCL_SNAP;
  2432.             bcopy(snap_ptr, dcl->dcl_snap, 5);
  2433.     
  2434.             /*
  2435.              * And put the bind structure back into its new proper place
  2436.              * in the hash table. dle_bind_hash_insert is called directly
  2437.              * here because dle_bind_enable has already been called for
  2438.              * this bind by dle_bind_req.
  2439.              */
  2440.             dle_bind_hash_insert(bind);
  2441.             break;
  2442.         case DL_PEER_BIND:
  2443.             /*
  2444.              * If this stream is bound to the SNAP sap, then we do not
  2445.              * allow it to be peer-bound to additional saps.  This may
  2446.              * be overly restrictive.
  2447.              */
  2448.             if (dcl->dcl_flags & F_DCL_SNAP)
  2449.                 return DL_OUTSTATE;
  2450.             /* Check also to be sure that a SNAP bind is not in progress. */
  2451.             flags = F_BIND_SNAP_PENDING | F_BIND_HASH | F_BIND_MATCH_LOCAL;
  2452.             bind = dle_bind_from_stuff(dcl, flags, 0xAA);
  2453.             if (bind != nilp(bind_t))
  2454.                 return DL_OUTSTATE;
  2455.     
  2456.             if (len != 2)
  2457.                 return DL_BADADDR;
  2458.     
  2459.             sap = (((UInt32)snap_ptr[0]) << 8) | (UInt32)snap_ptr[1];
  2460.             flags = F_BIND_HASH | F_BIND_MATCH_LOCAL;
  2461.             if  (sap == 0) {
  2462.                 /*
  2463.                  * Special OT promiscuous mode for receiving all
  2464.                  * 802 packets.
  2465.                  */
  2466.                 if (!(dcl->dcl_flags & F_DCL_802))
  2467.                     return DL_BADADDR;
  2468.                 flags = F_BIND_MATCH_ANY_802;
  2469.             } else if (sap <= 0xFE) {
  2470.                 /*
  2471.                  * Make sure that other saps bound to this stream are
  2472.                  * also 802 saps. We don't mix and match sap types.
  2473.                  */
  2474.                 if (sap == 0xAA  ||  !(dcl->dcl_flags & F_DCL_802))
  2475.                     return DL_BADADDR;
  2476.                 flags |= F_BIND_802;
  2477.             } else {
  2478.                 /*
  2479.                  * Don't allow a non-802 sap to be bound if we're
  2480.                  * already an 802 stream.
  2481.                  */
  2482.                 if (dcl->dcl_flags & F_DCL_802)
  2483.                     return DL_BADADDR;
  2484.     
  2485.                 /* Don't allow a subsbind to an IPX sap */
  2486.                 if (sap == 0xFF)
  2487.                     return DL_BADADDR;
  2488.     
  2489.                 /* And finally make sure that the Ether type is valid. */
  2490.                 if (sap > kMaxDIXSAP || sap < kMinDIXSAP)
  2491.                     return DL_BADADDR;
  2492.             }
  2493.     
  2494.             /* Create a new bind structure for this sap. */
  2495.             bind = dle_bind_alloc(dcl, sap, flags);
  2496.             if (bind == nilp(bind_t))
  2497.                 return DL_SYSERR;
  2498.     
  2499.             /* Propagate 802.2 status from toplevel bind. */
  2500.             if (dcl->dcl_flags & F_DCL_AUTO_TEST)
  2501.                 bind->bind_flags |= F_BIND_AUTO_TEST;
  2502.             if (dcl->dcl_flags & F_DCL_AUTO_XID)
  2503.                 bind->bind_flags |= F_BIND_AUTO_XID;
  2504.     
  2505.             /* Put the structure into its proper hash location. */
  2506.             dle_bind_enable(bind);
  2507.             break;
  2508.         default:
  2509.             return DL_UNSUPPORTED; 
  2510.     }
  2511.  
  2512.     /*
  2513.      * Turn around the DL_SUBS_BIND_REQ as a DL_SUBS_BIND_ACK. This works
  2514.      * because the ack structure is no bigger than the request.  Also note
  2515.      * that we have to copy the sap value into the right place before we
  2516.      * possibly overwrite it.
  2517.      */
  2518.     dlsba = (dl_subs_bind_ack_t *)mp->b_rptr;
  2519.     addr = (UInt8 *)&dlsba[1];
  2520.     bcopy(snap_ptr, &addr[0], len);
  2521.     dlsba->dl_primitive = DL_SUBS_BIND_ACK;
  2522.     dlsba->dl_subs_sap_offset = sizeof(*dlsba);
  2523.     dlsba->dl_subs_sap_length = len;
  2524.     mp->b_wptr = &addr[len];
  2525.     mp->b_datap->db_type = M_PCPROTO;
  2526.  
  2527.     qreply(q, mp);
  2528.     return 0;
  2529. }
  2530.  
  2531. /*
  2532.  * Handle DL_SUBS_UNBIND_REQ messages from dle_wput.  This routine removes
  2533.  * only one binding that was created by a previous DL_SUBS_BIND_REQ.  All
  2534.  * other binds on the stream are left alone.
  2535.  * dle_wput will pass a DL_OK_ACK or DL_ERROR_ACK upstream depending on the
  2536.  * return value.
  2537.  */
  2538. static int
  2539. dle_subs_unbind_req (queue_t * q, mblk_t * mp)
  2540. {
  2541.     dcl_t                    * dcl = (dcl_t *)q->q_ptr;
  2542.     bind_t                    * bind;
  2543.     UInt32                    flags;
  2544.     UInt32                    len;
  2545.     dl_subs_unbind_req_t    * dlsubr = (dl_subs_unbind_req_t *)mp->b_rptr;
  2546.     UInt32                    sap;
  2547.     UInt8                    * snap_ptr;
  2548.  
  2549.     if (dcl->dcl_state != DL_IDLE)
  2550.         return DL_OUTSTATE;
  2551.  
  2552.     /*
  2553.      * Verify that the DL_SUBS_UNBIND_REQ is properly formatted and get
  2554.      * a pointer to the sap (or snap) value in the message.
  2555.      */
  2556.     len = dlsubr->dl_subs_sap_length;
  2557.     snap_ptr = mi_offset_param(mp, dlsubr->dl_subs_sap_offset, len);
  2558.     if (snap_ptr == nilp(UInt8))
  2559.         return DL_BADADDR;
  2560.  
  2561.     /*
  2562.      * The length tells us if we're looking for a DL_HIERARCHICAL/SNAP
  2563.      * binding or if we're looking for a DL_PEER_BIND binding of an
  2564.      *  Ethertype or 802 type.
  2565.      */
  2566.         switch (len) {
  2567.         case 5:
  2568.             /* SNAP time. */
  2569.             sap = (((UInt32)snap_ptr[3]) << 8) | (UInt32)snap_ptr[4];
  2570.             flags = F_BIND_SNAP | F_BIND_802 | F_BIND_HASH;
  2571.     
  2572.             /* Find the bind structure for this sap. */
  2573.             bind = dle_bind_from_stuff(dcl, flags, sap);
  2574.             if (bind == nilp(bind_t))
  2575.                 return DL_BADADDR;
  2576.     
  2577.             /*
  2578.              * Fix the bind structure so a new DL_SUBS_BIND_REQ will succeed.
  2579.              */
  2580.             dle_bind_hash_remove(dcl_to_dle(dcl), bind);
  2581.             bind->bind_flags &= ~(F_BIND_SNAP | F_BIND_802);
  2582.             bind->bind_flags |= F_BIND_SNAP_PENDING;
  2583.             bind->bind_sap = 0xAA;
  2584.             dcl->dcl_flags &= ~F_DCL_SNAP;
  2585.             dcl->dcl_sap = 0xAA;
  2586.             dle_bind_hash_insert(bind);
  2587.             break;
  2588.         case 2:
  2589.             /* Ethertype or 802 type binding. */
  2590.             sap = (((UInt32)snap_ptr[0]) << 8) | (UInt32)snap_ptr[1];
  2591.     
  2592.             /*
  2593.              * Don't allow a subs unbind to remove the binding made
  2594.              * with a DL_BIND_REQ.
  2595.              */
  2596.             if (sap == dcl->dcl_sap)
  2597.                 return DL_BADADDR;
  2598.     
  2599.             flags = F_BIND_MATCH_LOCAL | F_BIND_HASH;
  2600.             if (sap <= 0xFE)
  2601.                 flags |= F_BIND_802;
  2602.     
  2603.             /* Special OT 802 promiscuous mode. */
  2604.             if (sap == 0)
  2605.                 flags = F_BIND_MATCH_ANY_802;
  2606.     
  2607.             /* Find the bind structure for this sap. */
  2608.             bind = dle_bind_from_stuff(dcl, flags, sap);
  2609.             if (bind == nilp(bind_t))
  2610.                 return DL_BADADDR;
  2611.             /*
  2612.              * Remove the structure from the hash table and from the dle's
  2613.              * list of binds.  Note that dle_bind_disable will also clean
  2614.              * up any promiscuous modes that may have been set on the bind.
  2615.              */
  2616.             dle_bind_disable(dcl_to_dle(dcl), bind);
  2617.             dle_bind_free(dcl_to_dle(dcl), bind);
  2618.             break;
  2619.         default:
  2620.             return DL_BADADDR;
  2621.     }
  2622.     return 0;
  2623. }
  2624.  
  2625. /*
  2626.  * Process DL_UNBIND_REQ messages from dle_wput. This routine removes all
  2627.  * bindings on a stream, whether they were created by DL_BIND_REQ or by
  2628.  * DL_SUBS_BIND_REQ messages. dle_wput will pass a DL_OK_ACK or DL_ERROR_ACK
  2629.  * upstream depending on the return value.
  2630.  */
  2631. static int
  2632. dle_unbind_req (queue_t * q, mblk_t * mp)
  2633. {
  2634.     dcl_t    * dcl = (dcl_t *)q->q_ptr;
  2635.  
  2636.     /* Make sure there is at least on bind active on the stream. */
  2637.     if (dcl->dcl_state != DL_IDLE)
  2638.         return DL_OUTSTATE;
  2639.  
  2640.     /*
  2641.      * Remove and delete all entries in the hash table associated
  2642.      * with this dcl.
  2643.      */
  2644.     dle_remove_all_my_binds(dcl);
  2645.     dcl->dcl_state = DL_UNBOUND;
  2646.  
  2647.     /* Flush all pending outbound messages. */
  2648.     flushq(q, FLUSHDATA);
  2649.     /*
  2650.      * Flush all inbound messages pending on the stream.  It is important
  2651.      * that this message go upstream before the DL_OK_ACK for the unbind.
  2652.      */
  2653.     flushq(RD(q), FLUSHDATA);
  2654.     putnextctl1(RD(q), M_FLUSH, FLUSHRW);
  2655.     
  2656.     return 0;
  2657. }
  2658.  
  2659. /*
  2660.  * Called by board code when this device is no longer available or is about to be
  2661.  * unloaded from memory (such as from its TerminateStreamModule routine).  This
  2662.  * routine releases all resources that have been allocated and associated with
  2663.  * the dle by the common DLPI code.
  2664.  */
  2665. void
  2666. dle_terminate (dle_t * dle)
  2667. {
  2668. }
  2669.  
  2670. /*
  2671.  * STREAMS write-side put procedure.  This routine is called by the
  2672.  * board-specific wput routine for all messages other than M_DATAs.
  2673.  * The parameters are the q and mp passed to the board-specific wput.
  2674.  */
  2675. mblk_t *
  2676. dle_wput (queue_t * q, mblk_t * mp)
  2677. {
  2678.     dcl_t                * dcl;
  2679.     mblk_t                * mp1;
  2680.     dblk_t                * db;
  2681.     UInt8                * dst;
  2682.     UInt8                * snap_ptr;
  2683.     UInt32                dest_addr_len;
  2684.     UInt8                * hdr;
  2685.     dle_t                * dle;
  2686.     UInt8                * rptr;
  2687.     dl_unitdata_req_t    * dlur;
  2688.     UInt8                * src;
  2689.     UInt32                len_or_sap, hdr_len;
  2690.     UInt32                flags;
  2691.  
  2692.     dcl = (dcl_t *)q->q_ptr;
  2693.     switch (mp->b_datap->db_type) {
  2694.         case M_PROTO:
  2695.         case M_PCPROTO:
  2696.             break;
  2697.         case M_IOCTL:
  2698.             return dle_wput_ioctl(q, mp);
  2699.         case M_FLUSH:
  2700.             if (*mp->b_rptr & FLUSHW)
  2701.                 flushq(q, FLUSHALL);
  2702.             if (*mp->b_rptr & FLUSHR) {
  2703.                 flushq(RD(q), FLUSHALL);
  2704.                 *mp->b_rptr &= ~FLUSHW;
  2705.                 qreply(q, mp);
  2706.                 return nilp(mblk_t);
  2707.             }
  2708.             freemsg(mp);
  2709.             return nilp(mblk_t);
  2710.         default:
  2711.             mi_strlog(q, 1, SL_TRACE | SL_ERROR,
  2712.              "dle_wput: unknown mp 0x%x db_type %d prim 0x%x\n",
  2713.               mp, mp->b_datap->db_type, *((long *)mp->b_rptr));
  2714.             freemsg(mp);
  2715.             return nilp(mblk_t);
  2716.     }
  2717.  
  2718.     /* Process all M_PROTO/M_PCPROTO DLPI messages. */
  2719.     rptr = mp->b_rptr;
  2720.     dlur = (dl_unitdata_req_t *)rptr;
  2721.     if ((mp->b_wptr - rptr) < sizeof(*dlur) || dlur->dl_primitive != DL_UNITDATA_REQ)
  2722.         return dle_wput_proto(q, mp);
  2723.  
  2724.     /*
  2725.      * Handle DL_UNITDATA_REQ messages from here.   First, make sure that
  2726.      * the message is properly formatted and we have the address bytes
  2727.      * needed. Also note that from here down, the interface MIB statistics
  2728.      * are incremented in some way whether for error or for success.
  2729.      */
  2730.     dle = dcl_to_dle(dcl);
  2731.     dest_addr_len = dlur->dl_dest_addr_length;
  2732.     dst = mi_offset_param(mp, dlur->dl_dest_addr_offset, dest_addr_len);
  2733.     if (dst == nilp(UInt8)) {
  2734.         dle->dle_istatus.transmit_errors++;
  2735.         return dle_wput_ud_error(mp, DL_BADADDR, 0);
  2736.     }
  2737.  
  2738.     /* Default header length is standard Ethernet. */
  2739.     hdr_len = 14;
  2740.     /*
  2741.      * Default formatting from dcl bind flags.  If the message contains sap
  2742.      * information, then that sap and requisite formatting will be used
  2743.      * instead of whatever was indicated in the bind.
  2744.      */
  2745.     flags = dcl->dcl_flags & (F_DCL_IPX | F_DCL_SNAP | F_DCL_802);
  2746.     snap_ptr = &dcl->dcl_snap[0];
  2747.  
  2748.     /* Determine formatting to be used for this packet. */
  2749.         switch (dest_addr_len) {
  2750.         case 6:
  2751.             if (flags & F_DCL_IPX) {
  2752.                 len_or_sap = 0;
  2753.                 break;
  2754.             }
  2755.             len_or_sap = dcl->dcl_sap;
  2756.             if (flags & F_DCL_SNAP)
  2757.                 hdr_len = 22;
  2758.             else if (flags & F_DCL_802)
  2759.                 hdr_len = 17;
  2760.             break;
  2761.         case 8:
  2762.             /* NOTE: for plain 802.2, only dst[7] matters, dst[6] is 0. */
  2763.             len_or_sap = (((UInt32)dst[6]) << 8) | (UInt32)dst[7];
  2764.             if (flags & F_DCL_SNAP)
  2765.                 hdr_len = 22;
  2766.             else if (flags & F_DCL_802)
  2767.                 hdr_len = 17;
  2768.             break;
  2769.         case 13:
  2770.             len_or_sap = (((UInt32)dst[11]) << 8) | (UInt32)dst[12];
  2771.             snap_ptr = &dst[8];
  2772.             hdr_len = 22;
  2773.             break;
  2774.         default:
  2775.             dle->dle_istatus.transmit_errors++;
  2776.             return dle_wput_ud_error(mp, DL_BADADDR, 0);
  2777.     }
  2778.  
  2779.     /*
  2780.      * Get enough space in the first mblk to hold the header, either by
  2781.      * reusing the DL_UNITDATA_REQ block or by allocating a new block.
  2782.      */
  2783.     hdr_len += dle->dle_xtra_hdr_len;
  2784.     mp1 = mp->b_cont;
  2785.     db = mp1->b_datap;
  2786.     hdr = mp1->b_rptr;
  2787.     if (db->db_type != M_DATA || db->db_ref != 1 || (hdr - db->db_base) < hdr_len) {
  2788.         db = mp->b_datap;
  2789.         if (db->db_ref == 1) {
  2790.             db->db_type = M_DATA;
  2791.             mp1 = mp;
  2792.         } else {
  2793.             mp1 = allocb(128, BPRI_LO);
  2794.             if (mp1 == nilp(mblk_t)) {
  2795.                 dle->dle_istatus.transmit_discards++;
  2796.                 return dle_wput_ud_error(mp, DL_SYSERR, ENOMEM);
  2797.             }
  2798.             mp1->b_cont = mp->b_cont;
  2799.         }
  2800.         hdr = mp1->b_rptr + hdr_len;
  2801.         mp1->b_wptr = hdr;
  2802.     }
  2803.  
  2804.     hdr_len -= dle->dle_xtra_hdr_len;
  2805.     hdr -= hdr_len;
  2806.     mp1->b_rptr = hdr;
  2807.  
  2808.     /* Set the destination address. */
  2809.     hdr[0] = dst[0];
  2810.     hdr[1] = dst[1];
  2811.     hdr[2] = dst[2];
  2812.     hdr[3] = dst[3];
  2813.     hdr[4] = dst[4];
  2814.     hdr[5] = dst[5];
  2815.  
  2816.     /* Set the SNAP information or simple 802 stuff, if necessary. */
  2817.     switch (hdr_len) {
  2818.         case 22:
  2819.             hdr[LLC_DSAP_OFFSET] = 0xAA;
  2820.             hdr[LLC_SSAP_OFFSET] = 0xAA;
  2821.             hdr[LLC_CONTROL_OFFSET] = LLC_DATA_VALUE;
  2822.             hdr[17] = snap_ptr[0];
  2823.             hdr[18] = snap_ptr[1];
  2824.             hdr[19] = snap_ptr[2];
  2825.             hdr[20] = (unsigned char)(len_or_sap >> 8);
  2826.             hdr[21] = (unsigned char)len_or_sap;
  2827.             len_or_sap = 0;        /* For common code below */
  2828.             break;
  2829.             
  2830.         case 17:
  2831.             hdr[LLC_DSAP_OFFSET] = len_or_sap;
  2832.             hdr[LLC_SSAP_OFFSET] = dcl->dcl_sap;
  2833.             hdr[LLC_CONTROL_OFFSET] = LLC_DATA_VALUE;
  2834.             len_or_sap = 0;        /* For common code below */
  2835.             break;
  2836.     }
  2837.  
  2838.     /*
  2839.      * Set either the sap or a 0 in the topmost header. If this value is
  2840.      * zero, then the board-specific code should write the actual length
  2841.      * of the packet into this area.  The board code must do this because
  2842.      * fast-path M_DATA messages are not passed through dle_wput.
  2843.      */
  2844.     hdr[12] = (unsigned char)(len_or_sap >> 8);
  2845.     hdr[13] = (unsigned char)len_or_sap;
  2846.  
  2847.     /* Set the source address. */
  2848.     src = dle->dle_current_addr;
  2849.     hdr[6] = src[0];
  2850.     hdr[7] = src[1];
  2851.     hdr[8] = src[2];
  2852.     hdr[9] = src[3];
  2853.     hdr[10] = src[4];
  2854.     hdr[11] = src[5];
  2855.  
  2856.     /*
  2857.      * If we allocated a new mblk for the header, then free the
  2858.      * DL_UNITDATA_REQ message.  This block cannot be deallocated until
  2859.      * the destination address and, possibly, sap/snap information is
  2860.      * copied into the header.
  2861.      */
  2862.     if (mp != mp1)
  2863.         freeb(mp);
  2864.     /*
  2865.      * b_rptr must be at start of any extra space for Fast Path to work.
  2866.      */
  2867.     mp1->b_rptr -= dle->dle_xtra_hdr_len;
  2868.     return mp1;
  2869. }
  2870.  
  2871. /* Create a DL_ERROR_ACK for the DLPI primitive in "mp". Called from dle_wput. */
  2872. static mblk_t *
  2873. dle_wput_error (queue_t * q, mblk_t * mp, int dl_err, int sys_err)
  2874. {
  2875.     dl_error_ack_t    * dlea = (dl_error_ack_t *)mp->b_rptr;
  2876.     size_t            len = mp->b_wptr - mp->b_rptr;
  2877.     UInt32            primitive;
  2878.  
  2879.     if (len < sizeof(dlea->dl_primitive)) {
  2880.         freemsg(mp);
  2881.         return nilp(mblk_t);
  2882.     }
  2883.     primitive = dlea->dl_primitive;
  2884.     freemsg(mp);
  2885.     mp = allocb(sizeof(*dlea), BPRI_HI);
  2886.     if (mp == nilp(mblk_t))
  2887.         return nilp(mblk_t);
  2888.     mp->b_datap->db_type = M_PCPROTO;
  2889.     dlea = (dl_error_ack_t *)mp->b_rptr;
  2890.     mp->b_wptr = (UInt8 *)&dlea[1];
  2891.     dlea->dl_primitive = DL_ERROR_ACK;
  2892.     dlea->dl_error_primitive = primitive;
  2893.     dlea->dl_errno = dl_err;
  2894.     dlea->dl_unix_errno = sys_err;
  2895.     return mp;
  2896. }
  2897.  
  2898. /* Handle all M_IOCTL messages for dle_wput. */
  2899. static mblk_t *
  2900. dle_wput_ioctl (queue_t * q, mblk_t * mp)
  2901. {
  2902.     mblk_t    * mp1, * mp2;
  2903.     struct iocblk * ioc;
  2904.     dcl_t    * dcl;
  2905.  
  2906.     dcl = (dcl_t *)q->q_ptr;
  2907.     ioc = (struct iocblk *)mp->b_rptr;
  2908.     switch (ioc->ioc_cmd) {
  2909.         case DL_IOC_HDR_INFO:
  2910.             /*            
  2911.              * Fast-path request.  First, allocate an mblk
  2912.              * to be used for the generated headers.  This mblk
  2913.              * is passed back to dle_wput as a zero-length
  2914.              * data packet.
  2915.              */
  2916.             mp2 = allocb(128, BPRI_LO);
  2917.             if (mp2 == nilp(mblk_t))
  2918.                 break;
  2919.             /* Make all the space available for headers. */
  2920.             mp2->b_wptr = mp2->b_datap->db_lim;
  2921.             mp2->b_rptr = mp2->b_wptr;
  2922.     
  2923.             mp1 = copyb(mp->b_cont);
  2924.             if ( mp1 == nilp(mblk_t) ) {
  2925.                 freeb(mp2);
  2926.                 break;
  2927.             }
  2928.     
  2929.             mp1->b_datap->db_type = M_PROTO;
  2930.             mp1->b_cont = mp2;
  2931.     
  2932.             /*
  2933.              * Call dle_wput back with a "normal" DL_UNITDATA_REQ
  2934.              * message.  The returned mblk will contain the
  2935.              * header to be used in fast-path M_DATA messages.
  2936.              */
  2937.             mp1 = dle_wput(q, mp1);
  2938.             if (mp1 == nilp(mblk_t))
  2939.                 break;
  2940.             if (mp1->b_datap->db_type != M_DATA) {
  2941.                 freemsg(mp1);
  2942.                 break;
  2943.             }
  2944.             mp->b_cont->b_cont = mp1;
  2945.     
  2946.             /*
  2947.              * Clear the per-stream flag so that inbound
  2948.              * non-multicast/broadcast packets will be
  2949.              * passed upstream as M_DATA messages.
  2950.              */
  2951.             dcl->dcl_flags &= ~F_DCL_NOT_FAST_PATH;
  2952. ok_ioctl:;
  2953.             ioc->ioc_count = 0;
  2954.             for (mp1 = mp; (mp1 = mp1->b_cont) != nilp(mblk_t); )
  2955.                 ioc->ioc_count += mp1->b_wptr - mp1->b_rptr;
  2956.             ioc->ioc_error = 0;
  2957.             mp->b_datap->db_type = M_IOCACK;
  2958.             return mp;
  2959.     
  2960.         case I_OTSetFramingType:
  2961.             /*
  2962.              * Open Transport ioctl.  As specified in the OT documentation,
  2963.              * setting the framing type only changes the mac type returned
  2964.              * in DL_INFO_ACK messages. Outbound packets are formatted 
  2965.              * according to the sap bound to the stream.
  2966.              */
  2967.             mp1 = mp->b_cont;
  2968.             if (mp1 == nilp(mblk_t) || (mp1->b_wptr - mp1->b_rptr) != sizeof(UInt32))
  2969.                 break;
  2970.             {
  2971.                 UInt32    framing_type = *(UInt32 *)mp1->b_rptr;
  2972.                 
  2973.                 if (framing_type != kOTGetFramingValue) {
  2974.                     dcl->dcl_framing_type = framing_type;
  2975.                     if (framing_type == kOTFraming8022)
  2976.                         dcl->dcl_mac_type = DL_CSMACD;
  2977.                     else
  2978.                         dcl->dcl_mac_type = DL_ETHER;
  2979.                 }
  2980.             }
  2981.             mp->b_cont = nilp(mblk_t);
  2982.             freeb(mp1);
  2983.             ioc->ioc_rval = dcl->dcl_framing_type;
  2984.             goto ok_ioctl;
  2985.     
  2986.         case I_OTSetRawMode:
  2987.         {
  2988.             dle_t                * dle = dcl_to_dle(dcl);
  2989.             dl_recv_control_t    * dlrc;
  2990.             unsigned long        len;
  2991.     
  2992.             mp1 = mp->b_cont;
  2993.             if (mp1 == nilp(mblk_t))
  2994.                 break;
  2995.             len = mp1->b_wptr - mp1->b_rptr;
  2996.             if (len < sizeof(dlrc->dl_primitive))
  2997.                 break;
  2998.             dlrc = (dl_recv_control_t *)mp1->b_rptr;
  2999.             switch (dlrc->dl_primitive) {
  3000.                 case kOTSetRecvMode:
  3001.                     {
  3002.                         unsigned int flags;
  3003.                         unsigned int dflags;
  3004.             
  3005.                         if (len < sizeof(dl_recv_control_t))
  3006.                             break;
  3007.             
  3008.                         flags = dlrc->dl_flags;
  3009.                         dflags = dcl->dcl_flags & ~(F_DCL_WANTS_RS_HEADER | F_DCL_WANTS_ERROR_PACKETS);
  3010.             
  3011.                         len = dcl_to_dle(dcl)->dle_istatus.mtu;
  3012.                         if (flags & DL_TRUNCATED_PACKET) {
  3013.                             if (dlrc->dl_truncation_length < len)
  3014.                                 len = dlrc->dl_truncation_length;
  3015.                         }
  3016.                         dcl->dcl_truncation_length = len;
  3017.                         dlrc->dl_truncation_length = len;
  3018.             
  3019.                         if (flags & DL_NORMAL_STATUS) {
  3020.                             dflags |= F_DCL_WANTS_RS_HEADER;
  3021.                             if (flags & DL_ERROR_STATUS) {
  3022.                                 if (dle->dle_hw.dlehw_recv_error_flags)
  3023.                                     dlrc->dl_flags |= dle->dle_hw.dlehw_recv_error_flags;
  3024.                                 dlrc->dl_flags |= DL_BAD_802_3_LENGTH;
  3025.                                 dflags |= F_DCL_WANTS_ERROR_PACKETS;
  3026.                             }
  3027.                         } else if (flags != 0) {
  3028.                             break;
  3029.                         }
  3030.             
  3031.                         dcl->dcl_flags = dflags;
  3032.                     }
  3033.                     ioc->ioc_rval = sizeof(dl_recv_status_t);
  3034.                     goto ok_ioctl;
  3035.                     
  3036.                 case kOTSendErrorPacket:
  3037.                     {
  3038.                         dl_send_control_t    * dlsc;
  3039.                         
  3040.                          if (len < sizeof(dl_send_control_t))
  3041.                             break;
  3042.                         dlsc = (dl_send_control_t *)dlrc;
  3043.                         mp1->b_rptr += sizeof(dl_send_control_t);
  3044.             
  3045.                         mp->b_cont = nilp(mblk_t);
  3046.                         ioc->ioc_count = 0;
  3047.                         ioc->ioc_error = 0;
  3048.                         ioc->ioc_rval = 0;
  3049.                         mp->b_datap->db_type = M_IOCACK;
  3050.             
  3051.                         if (dlsc->dl_flags & DL_BAD_802_3_LENGTH) {
  3052.                             qreply(q, mp);
  3053.                             return mp1;
  3054.                         }
  3055.             
  3056.                     if (dle->dle_hw.dlehw_send_error) {
  3057.                         ioc->ioc_error = (*dle->dle_hw.dlehw_send_error)(
  3058.                                 dle, mp1, dlsc->dl_flags);
  3059.                     } else
  3060.                         ioc->ioc_error = EINVAL;
  3061.                         return mp;
  3062.                     }
  3063.                 default:
  3064.                     break;
  3065.             }
  3066.         }
  3067.         break;
  3068.         
  3069.     default:
  3070.             /* Only NAK the ioctl if we don't recognize the command. */
  3071.             mp->b_datap->db_type = M_IOCNAK;
  3072.             ioc->ioc_error = EINVAL;
  3073.             return mp;
  3074.     }
  3075.     /* If there is a formatting error, then ACK the ioctl with an error. */
  3076.     mp->b_datap->db_type = M_IOCACK;
  3077.     ioc->ioc_error = EINVAL;
  3078.     return mp;
  3079. }
  3080.  
  3081. /* Handle all DLPI primitives except DL_UNITDATA_REQ from dle_wput. */
  3082. static mblk_t *
  3083. dle_wput_proto (queue_t * q, mblk_t * mp)
  3084. {
  3085.     mblk_t                * mp1;
  3086.     size_t                len;
  3087.     dl_info_req_t        * dlir = (dl_info_req_t *)mp->b_rptr;
  3088.     dle_dlpi_dispatch_t    * dledd = dle_dlpi_dispatch_table;
  3089.     int    err;
  3090.  
  3091.     err = DL_BADPRIM;
  3092.     len = mp->b_wptr - mp->b_rptr;
  3093.     if (len >= sizeof(dlir->dl_primitive)) {
  3094.         /*
  3095.          * Search the DLPI dispatch table for the routine to
  3096.          * handle this primitive.
  3097.          */
  3098.         for ( ; dledd < A_END(dle_dlpi_dispatch_table); dledd++ ) {
  3099.             if ( dledd->dledd_primitive == dlir->dl_primitive ) {
  3100.                 if (len < dledd->dledd_min_len)
  3101.                     break;
  3102.                 /* Create an mblk to hold the ACK message. */
  3103.                 mp1 = mi_reallocb(mp, dledd->dledd_reallocb_len);
  3104.                 if (mp1 == nilp(mblk_t)) {
  3105.                     err = DL_SYSERR;
  3106.                     break;
  3107.                 }
  3108.                 mp = mp1;
  3109.                 err = (*dledd->dledd_func)(q, mp);
  3110.                 break;
  3111.             }
  3112.         }
  3113.     }
  3114.  
  3115.     /* 
  3116.      * If we couldn't find the primitive or the handler returned an error,
  3117.      * then create a DL_ERROR_ACK message to go upstream.
  3118.      */
  3119.     if (err != 0) {
  3120.         return dle_wput_error(q, mp, err
  3121.                     , (err == DL_SYSERR) ? ENOMEM : 0);
  3122.     }
  3123.  
  3124.     /*
  3125.      * If there was no error, but the primitive requires a DL_OK_ACK
  3126.      * message, then create the ACK and pass it upstream.
  3127.      */
  3128.     if (dledd->dledd_flags & F_MIEDD_OK_ACK_NEEDED) {
  3129.         dl_ok_ack_t * dloa = (dl_ok_ack_t *)mp->b_rptr;
  3130.         
  3131.         dloa->dl_correct_primitive = dloa->dl_primitive;
  3132.         dloa->dl_primitive = DL_OK_ACK;
  3133.         mp->b_wptr = (UInt8 *)&dloa[1];
  3134.         mp->b_datap->db_type = M_PCPROTO;
  3135.         return mp;
  3136.     }
  3137.  
  3138.     /* Return NULL since we have consumed the message. */
  3139.     return nilp(mblk_t);
  3140. }
  3141.  
  3142. /*
  3143.  * Create a DL_UDERROR_IND message for dle_wput. This routine may also
  3144.  * be called directly from board-specific code.
  3145.  */
  3146. mblk_t *
  3147. dle_wput_ud_error (mblk_t * mp, int dlpi_err, int unix_err)
  3148. {
  3149.     UInt32                dest_addr_len;
  3150.     UInt8                local_addr[8];
  3151.     UInt8                * dst;
  3152.     dl_uderror_ind_t    * dlud;
  3153.     mblk_t                * mp1;
  3154.  
  3155.     strlog(0, 0, 1, SL_TRACE, "dle_wput_ud_error: dlpi_err %d, unix_err %d\n"
  3156.         , dlpi_err, unix_err);
  3157.         
  3158.     switch (mp->b_datap->db_type) {
  3159.         case M_PROTO:
  3160.         case M_PCPROTO:
  3161.         {
  3162.             dl_unitdata_req_t    * dlur = (dl_unitdata_req_t *)mp->b_rptr;
  3163.             size_t                len = mp->b_wptr - mp->b_rptr;
  3164.             UInt32                dest_addr_offset = dlur->dl_dest_addr_offset;
  3165.             
  3166.             dest_addr_len = dlur->dl_dest_addr_length;
  3167.             len -= dest_addr_offset;
  3168.             dst = &mp->b_rptr[dest_addr_offset];
  3169.             if (len < dest_addr_len)
  3170.                 dest_addr_len = 0;
  3171.         }
  3172.             break;
  3173.         case M_DATA:
  3174.             bcopy(mp->b_rptr, local_addr, 6);
  3175.             bcopy(mp->b_rptr + 12, local_addr + 6, 2);
  3176.             dest_addr_len = 8;
  3177.             dst = local_addr;
  3178.             break;
  3179.         default:
  3180.             freemsg(mp);
  3181.             return nilp(mblk_t);
  3182.     }
  3183.     mp1 = allocb(sizeof(dl_uderror_ind_t) + dest_addr_len, BPRI_HI);
  3184.     if (mp1 == nilp(mblk_t)) {
  3185.         freemsg(mp);
  3186.         return nilp(mblk_t);;
  3187.     }
  3188.     mp1->b_datap->db_type = M_PCPROTO;
  3189.     mp1->b_wptr = &mp1->b_rptr[sizeof(dl_uderror_ind_t) + dest_addr_len];
  3190.     dlud = (dl_uderror_ind_t *)mp1->b_rptr;
  3191.     dlud->dl_primitive = DL_UDERROR_IND;
  3192.     dlud->dl_dest_addr_length = dest_addr_len;
  3193.     dlud->dl_dest_addr_offset = sizeof(dl_uderror_ind_t);
  3194.     dlud->dl_unix_errno = unix_err;
  3195.     dlud->dl_errno = dlpi_err;
  3196.     if (dest_addr_len != 0)
  3197.         bcopy(dst, (char *)&dlud[1], dest_addr_len);
  3198.     freemsg(mp);
  3199.     return mp1;
  3200. }
  3201.  
  3202. /*
  3203.  * Handle DL_TEST_REQ, DL_TEST_RES, DL_XID_REQ and DL_XID_RES messages
  3204.  * from dle_wput. All of these messages have the same format with a
  3205.  * different DLPI primitive.
  3206.  */
  3207. static int
  3208. dle_xidtest (queue_t * q, mblk_t * mp)
  3209. {
  3210.     dcl_t                * dcl = (dcl_t *)q->q_ptr;
  3211.     dle_t                * dle;
  3212.     dl_test_req_t        * dtr;
  3213.     dl_unitdata_req_t    * dlur;
  3214.     UInt32                saved_flags;
  3215.     UInt32                primitive;
  3216.     UInt8                * rptr;
  3217.     UInt32                test_flag;
  3218.     UInt8                control_value;
  3219.  
  3220.     if (dcl->dcl_state != DL_IDLE)
  3221.         return DL_OUTSTATE;
  3222.     dle = dcl_to_dle(dcl);
  3223.  
  3224.     /* We can't send 802 test messages on non-802 streams. */
  3225.     if (!(dcl->dcl_flags & F_DCL_802))
  3226.         return DL_NOTSUPPORTED;
  3227.  
  3228.     /*
  3229.      * Make sure that the message is properly formatted and
  3230.      * we have the address bytes needed.
  3231.      */
  3232.     dtr = (dl_test_req_t *)mp->b_rptr;
  3233.     if (!mi_offset_param(mp, dtr->dl_dest_addr_offset, dtr->dl_dest_addr_length))
  3234.         return DL_BADADDR;
  3235.  
  3236.     /*
  3237.      * If the user previously requested automatic handling of Test
  3238.      * or XID messages, then give him an error now.
  3239.      */
  3240.     primitive = dtr->dl_primitive;        /* save for later */
  3241.     switch (primitive) {
  3242.         case DL_TEST_REQ:
  3243.         case DL_TEST_RES:
  3244.             if (dcl->dcl_flags & F_DCL_AUTO_TEST)
  3245.                 return DL_TESTAUTO;
  3246.             control_value = LLC_TEST_VALUE;
  3247.             break;
  3248.         case DL_XID_REQ:
  3249.         case DL_XID_RES:
  3250.             if (dcl->dcl_flags & F_DCL_AUTO_XID)
  3251.                 return DL_XIDAUTO;
  3252.             /*
  3253.              * If there is any data associated with the request,
  3254.              * then return an error.  The 802.2 spec states that
  3255.              * XID packets contain only 3 bytes of LLC information,
  3256.              * and we, the LLC layer, are responsible for generating
  3257.              * those 3 bytes.
  3258.              */
  3259.             if (mp->b_cont != nilp(mblk_t)) {
  3260.                 if (msgdsize(mp->b_cont) != 0)
  3261.                     return DL_BADDATA;
  3262.                 freemsg(mp->b_cont);
  3263.                 mp->b_cont = nilp(mblk_t);
  3264.             }
  3265.     
  3266.             /* Allocate an M_DATA block for the XID information field. */
  3267.             {
  3268.                 mblk_t    * mp1 = allocb(3, BPRI_HI);
  3269.                 if (mp1 == nilp(mblk_t))
  3270.                     return DL_SYSERR;
  3271.                 rptr = mp1->b_rptr;
  3272.                 mp1->b_wptr = rptr + 3;
  3273.                 rptr[0] = XID_FORMAT_IDENTIFIER;
  3274.                 rptr[1] = 0x1;        /* Type 1 LLC, non-NULL LSAP */
  3275.                 rptr[2] = 0;
  3276.                 mp->b_cont = mp1;
  3277.             }
  3278.             control_value = LLC_XID_VALUE;
  3279.             break;
  3280.         default:
  3281.             /* Shouldn't happen. */
  3282.             return DL_UNSUPPORTED;
  3283.     }
  3284.  
  3285.     /*
  3286.      * Convert the request/response to a DL_UNITDATA_REQ.
  3287.      * Ordering is important here.  Note that we don't set
  3288.      * dl_priority here, and we rely on dle_wput not examining
  3289.      * that field.
  3290.      */
  3291.     dlur = (dl_unitdata_req_t *)dtr;
  3292.     test_flag = dtr->dl_flag;    /* save for later */
  3293.     dlur->dl_primitive = DL_UNITDATA_REQ;
  3294.     dlur->dl_dest_addr_length = dtr->dl_dest_addr_length;
  3295.     dlur->dl_dest_addr_offset = dtr->dl_dest_addr_offset;
  3296.  
  3297.     /* If this is a SNAP-bound stream, pretend it isn't for dle_wput. */
  3298.     saved_flags = (dcl->dcl_flags & F_DCL_SNAP);
  3299.     dcl->dcl_flags &= ~F_DCL_SNAP;
  3300.  
  3301.     /* Call dle_wput to create the outbound M_DATA message. */
  3302.     mp = dle_wput(q, mp);
  3303.     dcl->dcl_flags |= saved_flags;
  3304.     if (mp == nilp(mblk_t))
  3305.         return DL_SYSERR;
  3306.  
  3307.     /* Copy the command information into the formatted packet. */
  3308.     rptr = &mp->b_rptr[dle->dle_xtra_hdr_len];
  3309.  
  3310.     if (saved_flags & F_BIND_SNAP)
  3311.         rptr[LLC_SSAP_OFFSET] = 0xAA;
  3312.     if (primitive == DL_TEST_RES  ||  primitive == DL_XID_RES)
  3313.         rptr[LLC_SSAP_OFFSET] |= LLC_RESPONSE_BIT;
  3314.     rptr[LLC_CONTROL_OFFSET] = control_value;
  3315.     if (test_flag)
  3316.         rptr[LLC_CONTROL_OFFSET] |= LLC_POLL_FINAL_FLAG;
  3317.  
  3318.     /* Transmit the packet by a lateral to the board's put routine. */
  3319.     put(q, mp);
  3320.     return 0;
  3321. }
  3322.